• 0

(Scripts) Random 5 times but not repetitive

Question

I need to set 5 random variables of scripts to i use so usualy i can do it by using "random(1;10)" but i want of each variable dont repeat the nunber used by the other so i want to aways z x c v b been diferent from each other, so how i can do it? My script sometimes make some var be identical to the other, plz help...

Edited by Xindage

Share this post


Link to post

23 answers to this question

  • 0

You're looking for a deck shuffler of some description. Here's a very straight forward one that puts 5 values between 1 and 10 into value a-e (should compile straight if my knowledge of ZDoom ACS is still on point):

#define MAX_SHUFFLE 10
int shuffleDeck[MAX_SHUFFLE];
int shufflePos = 0;
function void initShuffle(int min)
{
    // Create the list of possible values
    for(int i = 0; i < MAX_SHUFFLE; ++i)
    {
        shuffleDeck[i] = i + min;
    }
    
    // Shuffle the table around
    for(int i = MAX_SHUFFLE - 1; i >= 0; --i)
    {
        int rand = random(0, MAX_SHUFFLE - 1);
        int moveVal = shuffleDeck[i];
        shuffleDeck[i] = shuffleDeck[rand];
        shuffleDeck[rand] = moveVal;
    }
    
    // Set shuffle index back to the beginning
    shufflePos = 0;
}

// grabs a value from the deck, rotating when necesseary
function int pullShuffle(void)
{
    int ret = shuffleDeck[shufflePos];
    shufflePos = (shufflePos + 1) % MAX_SHUFFLE;
    return ret;
}

script 1 (void)
{
    initShuffle(1);
    int valuea = pullShuffle();
    int valueb = pullShuffle();
    int valuec = pullShuffle();
    int valued = pullShuffle();
    int valuee = pullShuffle();
}

 

Edited by Edward850

Share this post


Link to post
  • 0

If I understand the question, you need to do one variable first to a random number, then delay and loop and set the next one to another random number and then inside the loop compare against the first variable to see if it's the same; if so, continue the loop or else continue and do the same for the remaining 3.

Share this post


Link to post
  • 0
4 hours ago, Nevander said:

delay

Delay is not necessary in loops that are guaranteed to terminate in a finite number of iterations, which this one is, as the RNG never generates the same number infinitely. Even if it did, you could do this: For the first variable V1, generate a random number modulo M1. For each next variable VX, generate a random number modulo the previous variable's MX and increase this number by 1 for every previous variable that has smaller or equal value as this number's current value (reevaluated after each comparison with each previous variable). Then every variable will have a unique value, the distribution of randomness will be uniform, and the algorithm will always terminate in finite number of steps regardless of the RNG.

Edited by scifista42

Share this post


Link to post
  • 0

let me just ask another thing (since your scripting is most complex than i expected) i'm planning a Last Man Standing minigame it work like this

 

al players begin in a platform and they have to choose between 10 plataforms to stay before the main plat fall on acid after that half of these 10 plataforms is going to sink (the 5 random initial nunbers), them from these 5 remainin plataforms the survived players is going o choose between 9 and goes on until if more than 1 players get on final plat they'll get a plasma to finish the game off, so the variable numbers of i want to get is actualy the tag of floors ranging from 1 to 10 (5p) then 11 to 19 (4p) , 20 to 27 (4p), 28 to 34 (3p) and goes on, here is the example of the tree:

tree.png

So i dont need of actual 5 variables all the time, also counting the fact of i cant take 5 non-repeated nunbers from a range of 4 plataforms since i want only 2 to fall. i'll take a look more deep into it and figure if i can work around this script, if i set this has awsnered its because i figured how, else i'll back.

 

also your script dont compile by default and the gzdoom builder dont show me what is wrong i'll have to take a bit more deeper look.

Edited by Xindage

Share this post


Link to post
  • 0

Edward850's code implements the following algorithm: (which, as I've just realized, is more efficient than mine)

 

1. Generate a sequence of all distinct numbers that you are choosing from (in your case, the tags of sectors in a particular row).

2. Randomly permutate this sequence.

3. Take the first N items in the sequence as the choices (in your case, N is the number of platforms to be lowered).

Share this post


Link to post
  • 0
10 hours ago, scifista42 said:

Delay is not necessary in loops that are guaranteed to terminate in a finite number of iterations

I suggested a delay to prevent things happening on the same tic. I often have issues with things happening in the same tic that shouldn't (i.e. event B depends on event A having happened but both events have no separating delay).

Share this post


Link to post
  • 0

"Things happening on the same tic" is, generally, something completely normal. It can only be problematique when multiple scripts/thinkers run concurrently AND it's essential that a specific one of them should run before another. A sequence of computations within a single script is always safe from such problems, as the computations are being performed in a fixed, predictable order, determined by the script's structure.

Edited by scifista42

Share this post


Link to post
  • 0

For now yet i just dont found a way to make the script work has i intended, but i did a work around it creating varius pre-definied actions to each phase of gameplay for now i can consider this finished.

Share this post


Link to post
  • 0

Wanted to come back and post something I did for a map I am making, although I'm sure the shuffler thing above is probably more practical and whatnot, this is what I was trying to say.

 

This will work ok but it's best if you have a small number of randomization to do. Obviously if you need 50 random numbers and each number can only be 1-50 one time each, this will be EXTREMELY tedious. However for 5 this approach seems to be working fine. This was slimmed down to be a very basic example, my script has more going on too than just the numbers being assigned.

 

Spoiler

int usedNum1 = 0;
int usedNum2 = 0;
int usedNum3 = 0;
int usedNum4 = 0;
int usedNum5 = 0;

script 1 (void)
{
	// Generate first unique random number
	usedNum1 = Random(1, 5);
	Delay(1);

	// Generate second unique random number
	usedNum2 = Random(1, 5);
	if(usedNum2 == usedNum1)
	{
		while(usedNum2 == usedNum1)
		{
			usedNum2 = Random(1, 5);
			Delay(1);
		}
	}
	Delay(1);

	// Generate third unique random number
	usedNum3 = Random(1, 5);
	if(usedNum3 == usedNum1 || usedNum3 == usedNum2)
	{
		while(usedNum3 == usedNum1 || usedNum3 == usedNum2)
		{
			usedNum3 = Random(1, 5);
			Delay(1);
		}
	}
	Delay(1);

	// Generate fourth unique random number
	usedNum4 = Random(1, 5);
	if(usedNum4 == usedNum1 || usedNum4 == usedNum2 || usedNum4 == usedNum3)
	{
		while(usedNum4 == usedNum1 || usedNum4 == usedNum2 || usedNum4 == usedNum3)
		{
			usedNum4 = Random(1, 5);
			Delay(1);
		}
	}
	Delay(1);

	// Generate fifth unique random number
	usedNum5 = Random(1, 5);
	if(usedNum5 == usedNum1 || usedNum5 == usedNum2 || usedNum5 == usedNum3 || usedNum5 == usedNum4)
	{
		while(usedNum5 == usedNum1 || usedNum5 == usedNum2 || usedNum5 == usedNum3 || usedNum5 == usedNum4)
		{
			usedNum5 = Random(1, 5);
			Delay(1);
		}
	}
	Delay(1);
}

 

 

Share this post


Link to post
  • 0
9 minutes ago, Nevander said:

*Delay after every command*

-_-

Share this post


Link to post
  • 0
40 minutes ago, scifista42 said:

-_-

Wanna explain the condescending emote? There's nothing wrong with one-tic delays.

Share this post


Link to post
  • 0
2 hours ago, Nevander said:

Wanna explain the condescending emote?

It's how I feel when my effort goes to waste. Said effort refers to writing the explanations in my previous posts.

2 hours ago, Nevander said:

There's nothing wrong with one-tic delays.

Without delays, this script would run instantaneously. With delays, it will run indefinitely long. Given this particular script's purpose, I think the former would be preferable.

Share this post


Link to post
  • 0
7 hours ago, scifista42 said:

Without delays, this script would run instantaneously. With delays, it will run indefinitely long. Given this particular script's purpose, I think the former would be preferable.

That is true however you're looking at (at the most) a length of 9 tics. That goes by very quickly. Like I said before, the reason I even put any delays is because in the past I have had issue where I would do something like in the script where a random number is generated for one variable, then after a comparison takes place. I need to be absolutely 100% sure that the first value is set before it tries to be involved in any comparison operation. Thus, one tic delay.

 

In the example above there is nothing happening after the random numbers so there's no way to know if anything could conflict. You could easily add extra control to that script so that anything that uses those values would completely depend on that script having been finished.

 

For example in my actual version in my map, it assigns scripts to random lines by using the usedNum variables as the lineids for SetLineSpecial. Thus, you can't even use any of the next scripts until those tics have passed and the lines are set. This was the purpose for it, so that I could randomly assign lines 1-5 (6 in my map) with a set of scripts. Line id 1 might get script 21-26 but there's no telling which it will be and lines 2-6 cannot share the same script, thus the need for this.

Share this post


Link to post
  • 0
14 minutes ago, Nevander said:

Like I said before, the reason I even put any delays is because in the past I have had issue where I would do something like in the script where a random number is generated for one variable, then after a comparison takes place. I need to be absolutely 100% sure that the first value is set before it tries to be involved in any comparison operation. Thus, one tic delay.

wha

Share this post


Link to post
  • 0
Just now, Arctangent said:

wha

Example:

Thing_SpawnFacing(stuff);
NoiseAlert(0, 0);

I have had problems with something as simple as this where the spawned monster is not alerted because they spawn the same tic as the noise alert goes off. I usually do this instead to ensure the thing has been spawned in the map and is activated before alerting:

Thing_SpawnFacing(stuff);
Delay(1);
NoiseAlert(0, 0);

So naturally after having this problem I am adding one tic delays in crucial places. I don't care about the speed loss. For my purposes, something like 9 tics doesn't matter in the slightest because I am making the scripts unbreakable through extra control code.

Share this post


Link to post
  • 0

I do not think finding a single case where you need to insert a delay is a reasonable justification to completely misinterpret how a language works.

 

Especially when you seem to think that

int a = b + c
if( a > d ) {
}

occurs simultaneously.

 

It does not. It occurs sequentially. In the same tic, yes, but there's still a defined order within that tic where the variable declaration occurs first, then the if statement follows. There could be many reasons why NoiseAlert doesn't work with a freshly spawned monster - most likely it either has to do with a freshly spawned monster either not being able to listen to sound until after the tic it was spawned in passed, or there's a flaw with Thing_SpawnFacing itself when it comes to monsters and sound.

 

Still, there is no reason to try to bust down a wall with your head out of sheer stubbornness. You'll only shatter your skull.

Share this post


Link to post
  • 0

So why do I get problems by not using delays? Does it have anything to do with using functions? For my mod I am working on I spawn using custom functions which are called in place of things like Thing_SpawnFacing. The first thing they do is spawn though. But in my experience, anything that is called in the same tic might not work correctly unless a delay is added.

Share this post


Link to post
  • 0
9 hours ago, Arctangent said:

There could be many reasons why NoiseAlert doesn't work with a freshly spawned monster - most likely it either has to do with a freshly spawned monster either not being able to listen to sound until after the tic it was spawned in passed, or there's a flaw with Thing_SpawnFacing itself when it comes to monsters and sound.

 

Share this post


Link to post
  • 0

 

1 hour ago, Nevander said:

The first thing they do is spawn though. But in my experience, anything that is called in the same tic might not work correctly unless a delay is added.

Remember that we don't have household quantum processors. A single processor can only ever do one thing at a time, and thus a program can only ever do things in a linear order. Without multithreading (to which Doom playsims in any port have a resounding zilch, ignoring the aspect of the ACSVM being a single threaded processor as well), anything you do in an order must logically stay within that order. So either as Arctangent already suggested, waking up enemies on the same frame is being overruled by actions later on in the same tic, or feel free to freak out because you've just traveled to an alternative universe where the laws of physics and mathematics are different.

 

There is one slight quirk in ACS that's unobvious and can sometimes make this confusing: Unless you are using ACS_ExecuteWithResult (as it logically needs to return a result), executing scripts does not happen immediately, instead they are queued, and usually at the end of the stack (so until all other scripts are finished/waiting). Sort of like how multiple programs work on a single threaded processor within an OS. Custom functions however are not scripts and must execute as any other function would, especially as they usually need to return results.

Edited by Edward850

Share this post


Link to post
  • 0
10 hours ago, Nevander said:

Example:


Thing_SpawnFacing(stuff);
NoiseAlert(0, 0);

I have had problems with something as simple as this where the spawned monster is not alerted because they spawn the same tic as the noise alert goes off. I usually do this instead to ensure the thing has been spawned in the map and is activated before alerting:


Thing_SpawnFacing(stuff);
Delay(1);
NoiseAlert(0, 0);

So naturally after having this problem I am adding one tic delays in crucial places. I don't care about the speed loss. For my purposes, something like 9 tics doesn't matter in the slightest because I am making the scripts unbreakable through extra control code.

 

This might require a bit of explanation.

You are both right and wrong with your analysis. The main issue here is that spawning an actor does not fully set it up yet. A few things only get set when its thinker runs for the first time. That's why immediately doing things right after spawning may sometimes yield unexpected results.

 

However, gratuitously inserting delays just because is not a generic solution for 'crucial' code - it's only needed here due to the special circumstances.

 

Share this post


Link to post
  • 0
1 hour ago, Graf Zahl said:

However, gratuitously inserting delays just because is not a generic solution for 'crucial' code - it's only needed here due to the special circumstances.

But that's very much the problem. I don't know all the special circumstances, so by default now I use delay when I need to control events. Even if ACS does that already in sequence, I don't care. I am making sure it happens the way I want it to.

Share this post


Link to post
  • 0

No, you're really not. Making sure stuff happen the way you want it to would just be testing your scripts.

 

What you're doing is a lot closer to trying to destroy the sun because you were burnt by a candle once.

Share this post


Link to post
  • 0
14 hours ago, Nevander said:

(at the most) a length of 9 tics.

I said "indefinite" for a reason. Each of your while loops will run indefinitely many iterations until a good number is generated, and each iteration waits for a tic. So your script might run for tens, hundreds or thousands of tics in total. If the RNG was true RNG or if it was hacked to exclude certain values from possibly being generated, the script could even run infinitely - but with the existing RNG, it's not realistically expectable.

5 hours ago, Nevander said:

But in my experience, anything that is called in the same tic might not work correctly unless a delay is added.

The fundamental issue is not "in the same tic", but "in the wrong order". If a script works on some data, then waits for some time, then continues working on the same data with the assumption that the data are in the same state as before the waiting, but in fact some other script modified the data in the meantime while the first script was waiting, is another situation leading to incorrect behavior, despite the fact that there was delay in the script - in fact, the incorrect behavior was possible precisely because there was delay, because the second script wouldn't be able to modify data in the middle of the first script's execution if the first script ran from start to end without delay.

1 hour ago, Nevander said:

I don't know all the special circumstances,

Me neither, but identifying the non-special circumstances is easy. Assignment to variables, arithmetic operations, comparisons, information functions, changing properties of map objects, always take immediate full effect. On the other hand, interactions between thinkers may or may not work this way.

Edited by scifista42

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now