• 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!

How can I not repeat a random number even using randomize()?

FoxyOfJungle

Kazan Games
Hi!
My goal is to generate a final number in which it cannot be repeated, within a range of numbers from 1 to 5.
GML:
enum MINIGAME_TYPE {
    NOONE,
    LOCKER,
    MEMORY_GAME,
    SEQUENCER,
    SWIPE_CARD,
    TEST_TUBES,
    SIZE
}
I will only use it after NOONE and before SIZE.


1 - This is what happening:



Notice that MEMORY_GAME and SWIPE_CARD were repeated in a very "close" way, when in fact it should give way to other friends that have not been added yet. 😁

Let's say this is the repetition sequence:
[5, 2, 4, 2, 4]
2 and 4 were repeated, I want it to give way to new random numbers and not to be repeated.

What I expect:
[5, 2, 4, 1, 3]



2 - What I have:


GML:
function showThing() {
    static minigameRandomNumbers = [];

    var _randomId = function() {
        return irandom_range(MINIGAME_TYPE.NOONE + 1, MINIGAME_TYPE.SIZE - 1); // from 1 to 5
    }

    var _randomNumber = _randomId();
    array_push(minigameRandomNumbers, _randomNumber); // add the random number to the end of the array

    FINAL_NUMBER = _randomNumber; // ???


    // reset array if larger
    show_debug_message(minigameRandomNumbers); // show array contents
    if (array_length(minigameRandomNumbers) >= MINIGAME_TYPE.SIZE - 1) {
        minigameRandomNumbers = [];
    }
}
Obviously the function is incomplete because I don't want to show the atrocities I tried using loops. (just exaggerating).

But basically, I have a static array, that means it is declared only once, so I can add the new random values each time I use the function.
The problem is that these numbers are repeated (within the range of 1 to 5), I want them not to be repeated until I use all the numbers from 1 to 5.
When the size of the array passes the limit, I am resetting it to reinsert new non-repeatable random values.


I've tried to generate a random number and add it to an array, but I'm not able to understand how to proceed, I have a brain block, maybe because I’ve been programming for hours, I don’t know...


The numbers are repeated...


If anyone can help me with this I will be very grateful. :)
 
Last edited:

FoxyOfJungle

Kazan Games
Are you looking for Shuffling?

like ds_list_shuffle
But why would I shuffle the items? I can't understand why. Also, is there a way to not use ds_lists? Because this is kind of old, I’m avoiding it.
I tried to add the values to the array only if they don't exist, but my mind crashed... Thanks for the answer!
 

Roldy

Member
Your goal is simple and doable. Your expectations are flawed.

Probably the best analog to what you want to simulate is if you put 5 numbers in a bag, shake it up and then blindly select one number out of the bag. Continue until the bag is empty, fill the bag up again before selecting more numbers.

Something like this could work:

GML:
randomize();
bagOfNumbers = ds_list_create();

function fillAndShuffleBag(bagOfNumbers) {
    // Fill the bag will numbers 1 through 5
    for (var i = 1; i <= 5; i++) {
        ds_list_add(bagOfNumbers, i);
    }

    // Shuffle the numbers
    ds_list_shuffle(bagOfNumbers);
}

// Pull numbers out of the bag
function getANumber(bagOfNumbers) {
    var count = ds_list_size(bagOfNumbers);

    if (count <= 0) {
        fillAndShuffleBag(bagOfNumbers);
    }
  
    // Get the first number and remove it from bag
    var numberChosen = bagOfNumbers[| 0];
    ds_list_delete(bagOfNumbers, 0);
  
    return numberChosen;
}
 

Padouk

Member
Yeah it's possible without a ds_list. You just need to repeatly and randomly swap 2 elements in your array. have a look at: http://www.gmstutorials.com/Techniques/RandomArray/RandomArray.aspx

--

Why shuffling? Well maybe I don't understand your usecase..
But you seem to want exactly those five number: 1,2,3,4,5 in any random order.

[1,3,4,2,5]
[4,2,3,1,5]
[5,4,1,2,3]
... be creative here ;)

that's pretty much the same thing as creating the array [1,2,3,4,5] and shuffling it...

//Pseudo code:
global.minigame_sequence = [1,2,3,4,5]
global.minigame_sequence = shuffle(global.minigame_sequence) //now [5,2,3,4,1]
//
minigame = remove_last(global.minigame_sequence) //now [5,2,3,4]
run your minigame 1
//
minigame = remove_last(global.minigame_sequence) //now [5,2,3]
run your minigame 4
...
 
Last edited:

kupo15

Member
it can be even easier than that. Why can't you just add numbers to a list/array, then do irandom(0,array_length-1) and retrieve, delete that index?
 
1-Have a array 5 in length
2-Shuffle it
3-Use array_pop() to remove the top value in the array, which will give you your random number
4-When the array is depleted, repopulate it and start over
 

Joe Ellis

Member
If you want to stick with arrays you'll have to create your own shuffling function. One way of doing shuffling or randomly choosing values from a list is using "flagging", recording when a number or index is used so it knows if it's been used before or not. (Or how many times)
You basically create an array of 0's with a length of how many numbers there are that it could randomly choose from, then every time a number is generated, check the array at that index. If it's false, set\flag it to true and add the number to the list, else generate another number and repeat until the required amount of numbers have been added.

GML:
function generate_array_of_unique_numbers(_min, _max, length)
{

var
array,
flags,
num_added = 0,
i;

flags[_max] = 0
array[length] = 0

while num_added < length
{

i = irandom_range(_min, _max)

if !flags[i]
{
array[++num_added - 1] = i
flags[i] = true
}

}

return array
}
You could also make it have a limit of > 1, say each number can be used up to 5 times, by incrementing the flag and checking it's < 5.

You need to make sure the length is <= the range of numbers though, or it'll create an infinite loop. So you could put this at the start as a safety measure:

GML:
length = min(length, abs(_min - _max))
 
Last edited:

TheouAegis

Member
I think they just mean that is the old way of doing things in game maker. But, has been covered here many times now, simply using an array and shuffling the array is an even older method than using list.
 

xDGameStudios

GameMaker Staff
GameMaker Dev.
I talk about a shuffle method here using arrays (don't like using ds_list either)

[TEXT TUTORIAL] Keyword "static" Explained

here is the part:

GML:
function array_shuffle(_array) {
    static _shuffleFunc = function(obj1, obj2) { return choose(-1, 1); }; // This function doesn't need to be declared every time it is used.
    array_sort(_array, _shuffleFunc);
}

// Usage
static array = [1, 2, 3, 4, 5]; // Declared only once!
var b = array; // Store the reference of the array into a local var
b[0] = b[0]; // touch the array so it gets copied (the most performant way of copying an array)
array_shuffle(b);

// Done
PS: The idea of adding element by element is in fact just an illusion.
It doesn't matter if you have an array already filled up or not, just print the numbers one by one as if they were being added ;)
 
Last edited:
Top