[ZSCRIPT]RandomSequence for random nonrepeating numbers

Post your example zscripts/ACS scripts/etc here.
Forum rules
The Projects forums are only for projects. If you are asking questions about a project, either find that project's thread, or start a thread in the General section instead.

Got a cool project idea but nothing else? Put it in the project ideas thread instead!

Projects for any Doom-based engine (especially 3DGE) are perfectly acceptable here too.

Please read the full rules for more details.
User avatar
Sir Robin
Posts: 537
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

[ZSCRIPT]RandomSequence for random nonrepeating numbers

Post by Sir Robin »

Do you want to get some random numbers but not the same number more than once? You need a random sequence.

Here's the class code:

Code: Select all

class RandomSequence
{
	array<int> numbers;
	int nextIndex;
	double factor;
	bool justShuffled;
	bool PreventRepeats;
	
	static RandomSequence NewInstance(int FirstValue, int LastValue, double factor = 1.0, bool PreventRepeats=false)
	{
		//spawn
		RandomSequence newSequence = new("RandomSequence");
		
		//populate
		for (int i = FirstValue; i <= LastValue; i++) newSequence.numbers.push(i);

		newSequence.factor=factor;
		newSequence.PreventRepeats=PreventRepeats;
		
		newSequence.shuffle();
		
		return newSequence;
	}
	
	void shuffle()
	{
		int last=numbers[numbers.size()-1];
		
		int size=numbers.size();
		for (int i = 0; i < size; i++)
		{
			int next=random(0,size-1);
			int temp=numbers[i];
			numbers[i]=numbers[next];
			numbers[next]=temp;
		}
		
		if (PreventRepeats && numbers[0]==last && numbers.size()>1)
		{
			int next=random(1,size-1);
			numbers[0]=numbers[next];
			numbers[next]=last;
		}
		
		nextIndex=0;
		justShuffled=true;
	}
	
	int GetNext()
	{
		justShuffled=false;
		let thisNumber=numbers[nextIndex];
		nextIndex++;
		if (nextIndex >= numbers.size()) shuffle();
		return thisNumber;
	}

	double fGetNext()
	{
		return factor * GetNext();
	}
	
	void print()//for debugging
	{
		console.printf("Array from "..GetClassName()..":");
		if (!numbers.size()) console.printf("[EMPTY]");
		for (int i=0;i<numbers.size();i++)
			console.printf("["..i.."]"..numbers[i]..((factor==1.0)?"":" "..(factor*numbers[i])));
	}
}
And it's pretty easy to use. If you want numbers between 1 and 10 for example, put this somewhere in your init:
RandomSequence MyRandom=RandomSequence.NewInstance(1,10);
then in your code, instead of this:
let SomeNumber = random(1,10);
do this:
let SomeNumber = MyRandom.GetNext();


If you want fractions instead of integers, for example numbers between 1 and 2 in 0.25 increments, do this:
RandomSequence MyRandom=RandomSequence.NewInstance(4,8,0.25);
and get it like this:
let SomeNumber = MyRandom.fGetNext();

These sequences won't have any repeats, but a repeat is possible. Imagine you have a deck of 52 cards, you draw all the cards and the last one is the Ace of Spades. You shuffle the cards and draw the first one from the new deck. There is a 1/52 chance that this card will be the Ace of Spades, so it appears that there is a repeat in the sequence. If you want to prevent that from happening, set PreventRepeats to true:
RandomSequence MyRandom=RandomSequence.NewInstance(0,51,PreventRepeats:true);
On each shuffle it will check if the old last pick is the same as the new first pick and if so shuffle it back in.

I also created code for creating random number sequences in my sorting library but this is a streamlined version.

Return to “Script Library”