Question with do until

M

Midastouch

Guest
Hello everyone i have a little question.

I did a little project to store the coordinates of a pixel when i click on it.
I store these coordinates in an array : array[value]= [1 is an filled array / 0 is an empty array, x stored here, y stored here]

The thing is i randomly delete some array in the time.

As you can see below, both codes are similar, i just changed the do until :
- In the first case my array_size stay at 0, it doesn't works
-In the second case my array_size works perfectly

And i don't understand why. It seems that if i change the value of a variable in a do until the value of this variable stay the same?

GML:
if mouse_check_button_pressed(mb_left) {

    //Find the first empty slot   
    var value = 0;
    if array[value][0] = 1 {
        do {
            value +=1}
        until array[value][0] = 0;
    }
    //Fill an array with the first empty slot
    array[value] = [1, xxx, yyy];
    //cell[xxx][yyy].type_ = types_.fire;
    //cell[xxx][yyy].updated = update;

    //Look for the size of the array
    if array[array_size][0] = 0 {
        do {
            array_size -=1;
        }
        until array[array_size][0] = 1;
    }
}

Code:
//Value in grid
xxx = mouse_x div cellsize;
yyy = mouse_y div cellsize;

if mouse_check_button_pressed(mb_left) {

    //Find the first empty slot   
    var value = 0;
    if array[value][0] = 1 {
        do {
            value +=1}
        until array[value][0] = 0;
    }
    //Fill an array with the first empty slot
    array[value] = [1, xxx, yyy];
    //cell[xxx][yyy].type_ = types_.fire;
    //cell[xxx][yyy].updated = update;

    //Look for the size of the array
    var variable_to_find_size = array_size;
    if array[variable_to_find_size][0] = 0 {
        do {
            variable_to_find_size -=1;
        }
        until array[variable_to_find_size][0] = 1;
    }
    array_size = variable_to_find_size + 1;
}
 
L

LunaNightshade

Guest
Wouldn't it be easier to use a ds_list()? As those do have the functions ds_list_size (your array_size) and ds_list_insert to add a new value; it would simplify the code immensly.

And currently I am wondering what you are doing with array_size there. In the first one you haven't set array_size, or you have set it at 0. As you have already filled the position 0 with the code above, the if-statement is evaluating to false, and the do-until is not even executed.

In the second one you are also not executing the do-until. Your array_size will also work correctly, since you are basically just saying: increase it by one after I added something.
 

samspade

Member
I'm not sure I understand you question. I also think there's a lot of missing information. I would recommend stepping through this code in the debugger to inspect the values at every point and make sure they are what you expect them to be. I think this could could also be re-written to be a lot more understandable like this:

GML:
if mouse_check_button_pressed(mb_left) {

    for (var i = 0; i < array_length(array); i += 1) {
        if (array[i][0] == 0) {
            array[i] = [1, xxx, yyy];
            break;
        }  
    }

}
i is also the same as the array_size value you are looking for at this point. Also, if you're tracking the last position something was added to, you don't even need the loop (either for or do until) as you can just add it directly to that point and increase the counter e.g.

GML:
if mouse_check_button_pressed(mb_left) {
    array[array_size] = [i, xxx, yyy];
    array_size += 1;
}

//or if you want to be fancy
if mouse_check_button_pressed(mb_left) {
    array[array_size++] = [i, xxx, yyy];
}
Wouldn't it be easier to use a ds_list()? As those do have the functions ds_list_size (your array_size) and ds_list_insert to add a new value; it would simplify the code immensly.
In 2.3.1, arrays have all of the functions (except shuffle) that ds_lists have and some that lists don't such as sort and pop so in most cases there would be no reason to use a list anymore.
 
M

Midastouch

Guest
My problem is that i delete randomly some array
for exemple i have :
array[0] = [1,300,200]
array[1] = [1,600,200]
array[2] = [1,3,2]
array[3] = [1,1000,1]
array[4] = [1,800,900]
....
I delete the array[1], so the slot is free, i fill it with a new value if i left click, however the array_size don't change.
But if i have this :
array[0] = [1,300,200]
array[1] = [1,600,200]
array[2] = [1,3,2]
array[3] = [1,1000,1]
array[4] = [1,800,900]
and i left ckicl so i create a new slot :
array[5] = [1,300,2]
 
L

LunaNightshade

Guest
By deleting, do you mean you set the first number in your value to 0? Or do you actually remove the value from the array completely?

Still, the snippet samspade posted would fill it exactly the same:

GML:
if mouse_check_button_pressed(mb_left) {
    for (var i = 0; i < array_length(array); i += 1) {
        if (array[i][0] == 0) {
            array[i] = [1, xxx, yyy];
            break;
        } 
    }
}
It checks the existing entries, and on the first one where your first value is 0 sets the new set of coordinates. Then it stops the execution of the loop. Though i would also not be increase to the end of the current array_size.

(The online help is not really up-to-date about array functions in some cases)

So, if I interpret correctly what you want to do ...

GML:
if (mouse_check_button_pressed(mb_left)) { // On left click
var value_stored = false;
    // Iterate through the array
    for (var i = 0; i < array_length(array); i += 1) {
        if (array[i][0] == 0) { // "Empty slot found, store here"
            array[i] = [1, xxx, yyy];
            value_stored = true;
            break;
        } 
    }
if(!value_stored) { // Append value at the end
    array[array_length(array)] = [1, xxx, yyy];
    array_size++; //Increase size_variable by one
}
}
With that you only need to decrease array_size whenever you delete a set of numbers.
 
M

Midastouch

Guest
[/QUOTE]
With that you only need to decrease array_size whenever you delete a set of numbers.
[/QUOTE]

Indeed and that is the reason i used the do until. I don't really want to know the array_length(array) but the array_size.
For exemple :
array[0] = [1,300,200]
array[1] = [1,600,200]
array[2] = [1,3,2]
array[3] = [1,1000,1]
array[4] = [1,800,900]
array[5] = [1,300,2]
array[6] = [0,0,0]
array[7] = [0,0,0]
array[8] = [0,0,0]
array[9] = [0,0,0]

Here the array_length(array) = 8 but i want to have the array_size = 4.
 

samspade

Member
Indeed and that is the reason i used the do until. I don't really want to know the array_length(array) but the array_size.
For exemple :
array[0] = [1,300,200]
array[1] = [1,600,200]
array[2] = [1,3,2]
array[3] = [1,1000,1]
array[4] = [1,800,900]
array[5] = [1,300,2]
array[6] = [0,0,0]
array[7] = [0,0,0]
array[8] = [0,0,0]
array[9] = [0,0,0]

Hre the array_length(array) = 8 but i want to have the array_size = 4
I am confused. Neither of those things are right. Array length is 10 and array_size (assuming you mean how many are filled) is 6.
 
L

LunaNightshade

Guest
I am confused as well.
I also do not see the problem that you do
array_size--
when you "delete" and entry, and
array_size++
when you add an entry (you'd need to modify the one above).

There is no need to iterate over the whole array whenever you do ...
 
M

Midastouch

Guest
I think i explain my problem badly. I will try to start from 0 with an exemple

So in a create event i put this :

GML:
array[0]=[1,0,0]//active
array[1]=[0,0,0]//not active but if i left click on a pixel this will be fill in priority
array[2]=[1,0,0]//active
array[3]=[1,0,0]//active
array[4]=[0,0,0]//not active
array[5]=[0,0,0]//not active
And in a step event i want to use a for loop but ONLY for the "actives" arrays, by active i mean the arrays with array[a value][0] = 1, in this exemple i will loop in the array[1] even if it is not active, it's not really important because it will be filled fast.

So my array_length(array) will be equal to 6, but i don't really need this information.
As you can see the array 4 and 5 are for me usless they are not actives they won't be filled fast because the array[1] is the priority .
I just want to know the variable array_size ( this variable is the lenght of actives arrays) in this exemple it will be equal to 4.
 
L

LunaNightshade

Guest
So, why don't you set your array_size in the creation-event (to 3 in your latest example)?

The break: Keyword is like "until", and stops the loop from being executed.
Using break in that context is simpler, as you can refrain from using another comparison, as that is slow going.

You can still keep "array_size" as with the example given above - you just have to update the value with each change you do, and it is still correct.

And if you do want to go through the whole array, then you need array_length, as your do-until-approach will stop at the first 0 there is. (If you have two gaps with 0, then do-until will never give you the correct number of arrays with a 1 - the first is being filled, the second not, and that is where your code stops, leaving out any 1s after gap out of the count).

Simply keeping track from creation over each update of your array by an additional variable, called array_size, will keep your code running fast, as unneccesary iterations just slow everything down.

Coding isn't just about getting it to work somehow, it is also about doing things as optimized as possible.

Let me give you the examples:

GML:
//Create Event
array[0]=[1,0,0]//active
array[1]=[0,0,0]//not active but if i left click on a pixel this will be fill in priority
array[2]=[1,0,0]//active
array[3]=[1,0,0]//active
array[4]=[0,0,0]//not active
array[5]=[0,0,0]//not active
array[6]=[1,0,0]//active

array_size = 4
Code:
//Step Event


if (mouse_check_button_pressed(mb_left)) { // On left click
var value_stored = false;
    // Iterate through the array
    for (var i = 0; i < array_length(array); i += 1) {
        if (array[i][0] == 0) { // "Empty slot found, store here"
            array[i] = [1, xxx, yyy];
            array_size++; // Increase array-size by 1
            value_stored = true;
            break; // Stop iteration
        }
    }
//Contingency: If the value couldn't be stored because the array is "full" (all places occupied by a 1), append a new value
if(!value_stored) { // Append value at the end
    array[array_length(array)] = [1, xxx, yyy];
    array_size++; //Increase size_variable by one
    }
}
And when you "delete" a value:
Code:
array[x] = [0,0,0] //x is the position to "empty"
array_size--; //Decrease array_size by one
Here one more information: array_length is not a variable, but a built-in function.
I'd rather not use "open-ended" loops like while() or do-until, as these can much more easily result in infinite loops.

Or is there another reason you really want to use do-until ?
 
M

Midastouch

Guest
Thank you for your time
To fill the arrays i always fill the first empty array (that is ok)

The heart of the problem is that array_size it will not necessarily change if i delete a value, because the value that will be delete, is not necessary the last value.
array_size is just the lenght of actives arrays from 0 to the last active array even if only 1 array is active and it's the last

For exemple at step1 :
array[0]=[1,0,0]//active
array[1]=[0,0,0]//not active
array[2]=[1,0,0]//active
array[3]=[1,0,0]//active
array[4]=[0,0,0]//not active
array[5]=[1,0,0]//active
array[6]=[1,0,0]//active

So array_lenght = 7
array_size = 7

If at step 2 :
array[0]=[0,0,0]//not active
array[1]=[0,0,0]//not active
array[2]=[1,0,0]//active
array[3]=[1,0,0]//active
array[4]=[0,0,0]//not active
array[5]=[1,0,0]//active
array[6]=[1,0,0]//active

In this step i delete the array[0] but array_lenght and array_size stay the same
So array_lenght = 7
array_size = 7

If at step 3 :
array[0]=[1,0,0]//not active
array[1]=[0,0,0]//not active
array[2]=[1,0,0]//active
array[3]=[1,0,0]//active
array[4]=[0,0,0]//not active
array[5]=[0,0,0]//not active
array[6]=[0,0,0]//not active

In this step i fill array[0] but i delete array[5] and array[6]
So array_lenght =7
But array_size 4
 
L

LunaNightshade

Guest
Is there a reason to keep "not active" values in the array?
You could simply delete them completely:

array_delete(array, i, 1)

Then you won't have to jump through hoops to have an extra variable and skip values (keyword "continue") and loop over "empty" entries.

See: https://yal.cc/gamemaker-2-3-syntax-in-details/
 

Yal

šŸ§ *penguin noises*
GMC Elder
ds_lists handle this for you automatically, and if you're using this for the player inventory you probably don't want to delete the list a lot, so no need to worry about the manual resource handling for data structures. You can just put arrays into the ds_list with ds_list_add() and they get added to the end of the list automatically.
 

samspade

Member
The code I posted in my first response would do exactly what you want, but as other's have said, unless you need an array of a specific size at all times, it seems like this is a problem that would be handled much much easier with an array or a list. For an array you'd just use the pop and push commands. For example:

GML:
//adding to the array
if mouse_check_button_pressed(mb_left) {
    array_push(array, [1, xxx, yyy]);
}

//deleting from the end of the array
if (/*whatever your condition is*/) {
    array_pop(array);
}

//deleting a random value from the array
if (/*whatever your condition is*/) {
    array_delete(array, irandom(array_length(array)-1), 1);
}
With a list you would use list add and list delete. List doesn't have a pop, so the middle suggestion wouldn't work with a list, but the first and last example would after changing the functions to be the appropriate list functions.
 
Top