• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[Solved] A way to randomize variables in a checklist format?

Status
Not open for further replies.
Level 9
Joined
Mar 17, 2016
Messages
153
Hi,

I've recently gotten myself into a very complicated thing. What I'm looking to do is have, for instance, 15 different variables that all have unique info stored in them and randomly give 1 of the 15 variables to a player. However, the tricky part (for me at least) is that I do not want an already given variable to be given to the player a second time. It needs to be set aside once called upon.

Eg: In an event, a player receives variable #13. The next time the variable randomises it will exclude variable no.13 from the random number. If it goes again and the player gets #5, next roll will exclude #'s 5 AND 13. So, if the player rolls 14 times, there should be a 100% chance to get the single, final remaining number.


Is there a way to do this through GUI? I have absolutely 0 JASS knowledge & would be very appreciative for any advice/help
 
Level 6
Joined
Dec 31, 2017
Messages
138
Yes, definitely.

Make an real/integer array of 15.

Let N[A] = Ath element of the array.

Let T = number of taken numbers, by default T = 0.

When you pick a number:
Set R = random integer from 0 to (14-T).
Give N[R] to the player.
Move your array by 1:
For A from R to (14-T-1) {
N[A] = N[A+1].​
}​
Increase T by 1.
 
Level 9
Joined
Mar 17, 2016
Messages
153
Deserted, you are truly a legend. Thank you so much. I've attempted to implement what you've said however I'm very uncertain as to whether or not I got it right, especially since I want it to be multiplayer friendly so I needed to add in more arrays to ensure they don't cross over when someone performs an action.

Does this look correct/did I screw something up?

  • Selection Setup
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet RQTracker_N_PLYR[1] = 1
      • Set VariableSet RQTracker_N_PLYR[2] = 2
      • Set VariableSet RQTracker_N_PLYR[3] = 3
      • Set VariableSet RQTracker_N_PLYR[4] = 4
      • Set VariableSet RQTakenNumbers_T_PLYR[1] = 0
  • RandomQuestion
    • Events
      • Dialog - A dialog button is clicked for Race_Dialog_0_Setup
    • Conditions
      • (Triggering player) Equal to Player 1 (Red)
    • Actions
      • Set VariableSet RQRandomizer_R_PLYR[1] = ((Random integer number between 1 and 14) - RQTakenNumbers_T_PLYR[1])
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • RQRandomizer_R_PLYR[1] Equal to 1
        • Then - Actions
          • Dialog - Show Race_Dialog_1 for Player 1 (Red)
          • For each (Integer RQTracker_N[1]) from RQRandomizer_R_PLYR[1] to (14 - (RQTakenNumbers_T_PLYR[1] - 1)), do (Set VariableSet RQTracker_N[1] = RQTracker_N[(1 + 1)])
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • RQRandomizer_R_PLYR[1] Equal to 2
        • Then - Actions
          • Dialog - Show Race_Dialog_2 for Player 1 (Red)
          • For each (Integer RQTracker_N[2]) from RQRandomizer_R_PLYR[1] to (14 - (RQTakenNumbers_T_PLYR[1] - 1)), do (Set VariableSet RQTracker_N[2] = RQTracker_N[(2 + 1)])
        • Else - Actions
        • Else - Actions

Also, I'm planning on having 5 players total in a game- would I need to create an instance of "N" for each player?

Forgive me, I'm really struggling to understand all this...
 

Wrda

Spell Reviewer
Level 28
Joined
Nov 18, 2012
Messages
2,010
You don't need to have every variable as array, only the RQTracker_Playerblablabla. I'm not sure what you're trying to do with the dialogs, if they're different for each player or not, but if it is then the dialog variable should be array.
I took the liberty to put the deserted's idea into triggers.
Be warned, the indexes here start at 0 and end at 4, which means it's still 5 elements or whatever you may call it. If you're going to use them as players then start at index 1. You won't need the Player((RQRandomizer + 1)) thing.
  • Melee Initialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet RQTracker[0] = 0
      • Set VariableSet RQTracker[1] = 1
      • Set VariableSet RQTracker[2] = 2
      • Set VariableSet RQTracker[3] = 3
      • Set VariableSet RQTracker[4] = 4
      • Set VariableSet RQTakenNumbers = 0
  • Randomize
    • Events
      • Player - Player 1 (Red) types a chat message containing random as An exact match
    • Conditions
    • Actions
      • Set VariableSet RQRandomizer = (Random integer number between 0 and RQTakenNumbers)
      • -------- use RQTracker[RQRandomizer] for all your actions --------
      • -------- e.g: --------
      • Dialog - Show Dialog[(RQRandomizer + 1)] for (Player((RQRandomizer + 1)))
      • For each (Integer RQLoop) from 0 to ((4 - RQTakenNumbers) - 1), do (Actions)
        • Loop - Actions
          • Set VariableSet RQTracker[RQLoop] = RQTracker[(RQLoop + 1)]
      • Set VariableSet RQTakenNumbers = (RQTakenNumbers + 1)
Basically, Deserted's idea is to keep the index order while picking a random one and removing it.
So...
Indexes: 1 2 3 4 5
3 is picked.
Loop and reassign 3 to 4 and 4 to 5
Indexes: 1 2 3 4
 
Level 9
Joined
Mar 17, 2016
Messages
153
Wrda, you as well have made my day. Many thanks to you. However, I can't seem to get this to work and all the math involved with this is something I have a lot of trouble working out my myself. I set it up as you've shown (or at least I think I did...) and it doesn't seem to function.

To clear things up on 'what' it is I'm even doing with this; there will be an item in a shop where once bought it will bring up a series of random questions. The reason I'm trying to add arrays to the variables is so that when another player comes up and tries to take the questionnaire it does not interfere with the person who is still taking it. (EG. If P1 gets question 10 it does not mean that P2/3/4/5 can no longer see question 10.)

Hopefully you, or someone else, can take a look here and let me know what I'm doing wrong.

  • RQuestionTest P1Red
    • Events
      • Dialog - A dialog button is clicked for Race_Dialog_0_Setup
      • Dialog - A dialog button is clicked for Race_Dialog[1]
      • Dialog - A dialog button is clicked for Race_Dialog[2]
      • Dialog - A dialog button is clicked for Race_Dialog[3]
      • -------- this goes to 15 --------
      • Dialog - A dialog button is clicked for Race_Dialog[15]
    • Conditions
      • (Triggering player) Equal to Player 1 (Red)
      • -------- this will be P2 (Blue) in another identical trigger --------
    • Actions
      • Set VariableSet RQRandomizer_R_PLYR[1] = (Random integer number between 1 and RQTakenNumbers_T_PLYR[1])
      • Dialog - Show Race_Dialog[(RQRandomizer_R_PLYR[1] + 1)] for Player 1 (Red)
      • For each (Integer RQLoop) from 1 to ((15 - RQTakenNumbers_T_PLYR[1]) - 1), do (Actions)
        • Loop - Actions
          • Set VariableSet RQTracker_N[RQLoop] = RQTracker_N[(RQLoop + 1)]
      • Set VariableSet RQTakenNumbers_T_PLYR[1] = (RQTakenNumbers_T_PLYR[1] + 1)
  • Race Selection Setup
    • Events
      • Time - Elapsed game time is 0.50 seconds
    • Conditions
    • Actions
      • Set VariableSet RQTracker_N[1] = 1
      • Set VariableSet RQTracker_N[2] = 2
      • Set VariableSet RQTracker_N[3] = 3
      • Set VariableSet RQTracker_N[4] = 4
      • Set VariableSet RQTracker_N[5] = 5
      • Set VariableSet RQTracker_N[6] = 6
      • Set VariableSet RQTracker_N[7] = 7
      • Set VariableSet RQTracker_N[8] = 8
      • Set VariableSet RQTracker_N[9] = 9
      • Set VariableSet RQTracker_N[10] = 10
      • Set VariableSet RQTracker_N[11] = 11
      • Set VariableSet RQTracker_N[12] = 12
      • Set VariableSet RQTracker_N[13] = 13
      • Set VariableSet RQTracker_N[14] = 14
      • Set VariableSet RQTracker_N[15] = 15
      • Set VariableSet RQTakenNumbers_T_PLYR[1] = 0
      • -------- -------------------0------------------ --------
      • Dialog - Change the title of Race_Dialog_0_Setup to Answer the followin...
      • Dialog - Create a dialog button for Race_Dialog_0_Setup labelled OK
      • Set VariableSet Race_Dialog_Button_0_Setup[0] = (Last created dialog Button)
      • Dialog - Create a dialog button for Race_Dialog_0_Setup labelled On second thought...
      • Set VariableSet Race_Dialog_Button_0_Setup[1] = (Last created dialog Button)
      • -------- below will be the questions 1-15 --------
      • Dialog - Change the title of Race_Dialog[1] to blah blah blah...
  • ShopPageCycle
    • Events
      • Unit - A unit Sells an item (from shop)
    • Conditions
    • Actions
      • Set VariableSet TempPlayer = (Owner of (Buying unit))
      • Set VariableSet TempPlayerInteger = (Player number of TempPlayer)
      • If (((Owner of (Buying unit)) Equal to Player 1 (Red)) and ((Item-type of (Sold Item)) Equal to Take the Questionarre)) then do (Dialog - Show Race_Dialog_0_Setup for Player 1 (Red)) else do (Do nothing)



When I buy the item it will show Race_dialog_0_setup, however when I click a button the menu simply vanishes. The questions are in an array of their own, independent from the setup.
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,285
Players cannot be given variables. It would be like a person eating data. The concepts are philosophically incompatible.

You can map data to players. This data could be a reference to other data such as an array index which can be used with an array variable to retrieve data. It looks like this concept was explained above.

To clear things up on 'what' it is I'm even doing with this; there will be an item in a shop where once bought it will bring up a series of random questions. The reason I'm trying to add arrays to the variables is so that when another player comes up and tries to take the questionnaire it does not interfere with the person who is still taking it. (EG. If P1 gets question 10 it does not mean that P2/3/4/5 can no longer see question 10.)
Use an array of player groups. The idea is that the question entities have a member that represents which players have done the question. When a player answers a question you add them to the player group for that question.

When selecting a question one iterates through all questions and add the indices of questions that do not contain the triggering player inside their player group to an array list. One can then randomly select an index from this array list to give the player a unique question which they have not already seen. The array list is emptied each time so it only ever contains the list of possible questions for the current player.

To prevent multiple players doing the same question at the same time you can add another member to the question entity representing if the question is currently being answered. This could be a Boolean that defaults to false and is set true when a player has been allocated a question and set back false again after the question has been answered. One would extend the possible question list generation code (described above) to only add questions which have that Boolean currently false.
 
Level 9
Joined
Mar 17, 2016
Messages
153
Use an array of player groups. The idea is that the question entities have a member that represents which players have done the question. When a player answers a question you add them to the player group for that question.

When selecting a question one iterates through all questions and add the indices of questions that do not contain the triggering player inside their player group to an array list. One can then randomly select an index from this array list to give the player a unique question which they have not already seen. The array list is emptied each time so it only ever contains the list of possible questions for the current player.
I absolutely do not understand this in any way whatsoever. I've been trying to figure it out but it's not working for me. Is there any way someone can show me what this looks like?

Edit: I don't need the final part, just what's quoted here.
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
  • Events
    • Time - Elapsed game time is 0.00 seconds
  • Conditions
  • Actions
    • Set MAX_THINGS = 15
    • For each (Integer A) from 1 to MAX_THINGS do (Actions)
      • Loop - Actions
        • Set HasBeenGivenThing[(Integer A)] = (Empty player group)
  • Set ThingPlayer = (Triggering Player) //or whatever
  • Set NotGivenCount = 0
  • For each (Integer A) from 1 to MAX_THINGS do (Actions)
    • Loop - Actions
      • If (All conditions are true) then do (Then actions) else do (Else actions)
        • If - Conditions
          • (HasBeenGivenThing[(Integer A)] contains ThingPlayer) equal to False
        • Then - Actions
          • Set NotGivenCount = (NotGivenCount + 1)
          • Set RandomThing[NotGivenCount] = (Integer A)
        • Else - Actions
  • If (All conditions are true) then do (Then actions) else do (Else actions)
    • If - Conditions
      • NotGivenCount Greater than 0
    • Then - Actions
      • Set ThingToGive = RandomThing[(Random integer between 1 and NotGivenCount)]
      • Player Group - Add ThingPlayer to HasBeenGivenThing[RandomThing]
      • //Give the ThingToGive'th thing
    • Else - Actions
      • //Can't give any more things because they've all been given
 
Level 9
Joined
Mar 17, 2016
Messages
153
@Pyrogasm thank you, it took me a long time but I think I finally have it figured out for the most part. I only have 2 questions that I can't figure out on my own.

1) At the first trigger group, it says "Set HasBeenGivenThing[(Integer A)] = (Empty player group)" I can't find any setting to set a playergroup to empty, it only allows me to select things like this (or a list of players from 1 to 24, including Neut. Hostile, Neut. Passive, etc.)

playerg.jpg


2)At the very end during the "Player Group - Add ThingPlayer to HasBeenGivenThing[RandomThing]" function, I notice you've managed to put an integer (RandomThing) with an array in without the array attached. Is this a new variable, or is it the same one that should have an array? If so, how is this accomplished?
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,285
1) At the first trigger group, it says "Set HasBeenGivenThing[(Integer A)] = (Empty player group)" I can't find any setting to set a playergroup to empty, it only allows me to select things like this (or a list of players from 1 to 24, including Neut. Hostile, Neut. Passive, etc.)
Set the size of the array. It will initialize all indices up to size with an empty player group making those actions unnecessary.

Otherwise custom script will need to be used. The following sets the player group variable "TempPlayerGroup" to a new empty group which can then be transferred to another variable using standard GUI actions.
JASS:
set udg_TempPlayerGroup = CreateForce()
2)At the very end during the "Player Group - Add ThingPlayer to HasBeenGivenThing[RandomThing]" function, I notice you've managed to put an integer (RandomThing) with an array in without the array attached. Is this a new variable, or is it the same one that should have an array? If so, how is this accomplished?
Appears to be a typo. The action likely should read...
  • Player Group - Add ThingPlayer to HasBeenGivenThing[ThingToGive]
 
Level 9
Joined
Mar 17, 2016
Messages
153
It looks like I finally got it working. Now, the only step is to make sure it works flawlessly while multiple users are taking it at the same time which I will test at a later date. I want to give a massive thank you to everyone who chimed in to help me and for being patient as well. It's awesome to have such a helpful community for wc3 mapping. Thank you all, +rep too.


Edit: I spoke too soon, it seems. The point of this was so that the questions would be random every time, but I'm noticing they are given to the player in a specific sequence: 14, 15, 10, 4, 5, 1, 7, 3, 12, 13, 14(again), 11, 8, 2, 9, 6

Not sure if that has significance, but that's the order they appear every time.
Also, somehow 14 has snuck in there for a second time.

Any thoughts on why this might be?
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,285
Any thoughts on why this might be?
World Editor defaults to testing maps with a fixed seed. Hence the same sequence of RNG calls results in the same rolls. One can turn off this option for testing.

In multiplayer the RNG is seeded before every game start. Hence this is of no consequence.
Also, somehow 14 has snuck in there for a second time.
Off by one error? Maybe when building a list of possible questions.

You can debug the trigger by printing messages at the various stages of execution. For example you could print the state of all the questions after one is selected to confirm that the questions are changing as expected. One could also print the list of selected possible questions before one is picked to see that it is selecting the questions correctly.

Without seeing your triggers all we can do is guess as to what the cause is.
 
Level 9
Joined
Mar 17, 2016
Messages
153
World Editor defaults to testing maps with a fixed seed. Hence the same sequence of RNG calls results in the same rolls. One can turn off this option for testing.

In multiplayer the RNG is seeded before every game start. Hence this is of no consequence.
Ah, I never would've guessed. Your insight is on another level.

Without seeing your triggers all we can do is guess as to what the cause is.
I'll post my triggers here in case, but I'm now wondering if it's because of the aforementioned 'issue' of the default seed. It could also be this additional trigger that I've added to initialize the whole thing, maybe it doesn't count the first question asked.

Edit: skip this, issue is resolved.

  • Test
    • Events
      • Dialog - A dialog button is clicked for Race_Dialog[1]
      • Dialog - A dialog button is clicked for Race_Dialog[2]
      • Dialog - A dialog button is clicked for Race_Dialog[3]
      • Dialog - A dialog button is clicked for Race_Dialog[4]
      • Dialog - A dialog button is clicked for Race_Dialog[5]
      • Dialog - A dialog button is clicked for Race_Dialog[6]
      • Dialog - A dialog button is clicked for Race_Dialog[7]
      • Dialog - A dialog button is clicked for Race_Dialog[8]
      • Dialog - A dialog button is clicked for Race_Dialog[9]
      • Dialog - A dialog button is clicked for Race_Dialog[10]
      • Dialog - A dialog button is clicked for Race_Dialog[11]
      • Dialog - A dialog button is clicked for Race_Dialog[12]
      • Dialog - A dialog button is clicked for Race_Dialog[13]
      • Dialog - A dialog button is clicked for Race_Dialog[14]
      • Dialog - A dialog button is clicked for Race_Dialog[15]
    • Conditions
    • Actions
      • Set VariableSet RQThingPlayer = (Triggering player)
      • Set VariableSet RQNotGivenCount = 0
      • For each (Integer A) from 1 to RQMAX_THINGS, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (RQThingPlayer is in RQHasBeenGivenThing[(Integer A)].) Equal to False
            • Then - Actions
              • Set VariableSet RQNotGivenCount = (RQNotGivenCount + 1)
              • Set VariableSet RQRandomThing[RQNotGivenCount] = (Integer A)
            • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • RQNotGivenCount Greater than 0
        • Then - Actions
          • Set VariableSet RQThingToGive = RQRandomThing[(Random integer number between 1 and RQNotGivenCount)]
          • Player Group - Add RQThingPlayer to RQHasBeenGivenThing[RQThingToGive]
          • Dialog - Show Race_Dialog[RQThingToGive] for RQThingPlayer
        • Else - Actions
  • Untitled Trigger 002
    • Events
      • Dialog - A dialog button is clicked for Race_Dialog_0_Setup
    • Conditions
    • Actions
      • Set VariableSet RQThingPlayer = (Triggering player)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Clicked dialog button) Equal to Race_Dialog_Button_0_Setup[0]
        • Then - Actions
          • Dialog - Show Race_Dialog[(Random integer number between 1 and RQMAX_THINGS)] for RQThingPlayer
        • Else - Actions
          • Do nothing
Edit: Now that I see it all laid out it's easy to spot that the problem IS the setup trigger. I'm sure that I can work out how to fix this it's probably ridiculously simple, so I'm setting this as solved for the 2nd time. Once again I want to give a massive thanks.

Cheers
 
Last edited:
Status
Not open for further replies.
Top