This question is about the ARC JavaScript command: Utility.getRandomUnique.
I know there are two Utility random functions: Utility.getRandom and Utility.getRandomUnique. The one I mentioned first, Utility.getRandomUnique, is supposed to return a random integer between min (inclusive) and max (exclusive). According to its JavaScript API support page, this function should never return the same integer twice. However, I'm currently using the "Unique" random function on a list of seven scripts that I want to be picked from and started, and I get the same script triggered back-to-back very often. Is this function broken in ARC? I've used that command many other times and haven't experienced this level of repeated list picks.
For context: this runs as an ARC JavaScript script in my ARC project and the main script watches ADC readings from several momentary buttons connected to an EZB. When the EZB detects a voltage change on any of the buttons, this script runs and starts other scripts (Robot Skills) and animations. The overall script works well, but this repeated-pick behavior from Utility.getRandomUnique is frustrating. I can post the entire script if needed.
Any info is welcome.
Below is the section of a larger script that uses Utility.getRandomUnique. I reformatted the code for readability but did not change variable names or logic:
//-----------------------------------------------------------------------------
// This section will pause the already running "Personality Generator" & "Weather Loop" scripts.
// Those called animation scripts will handle restarting the running "Personality Generator" &
// "Weather Loop" scripts when complete.
// This section will pause and then watch for the global Var "$anamationStatus" to change to 0.
// 0 is set by the called animation scripts showing that they are complete. Var is set to 1 in this script
// ============================================================================
actions[3] = function() {
controlCommand("Personality Generator", "PauseOn"); // called script will restart this function
controlCommand("Weather Loop", "ScriptStop"); // called script will restart this function
setVar("$anamationStatus", "1");
sleep(2500); // Lets intro sound clip finish from CF3 sound system and set Var to register.
var animationList = [
"Attack",
"Danger! Danger!",
"It's Launch Plus 8 Hours",
"Pledge of Allegience",
"Sing it",
"Threat",
"Take a soil sample"
];
// pick one random animation
var randomIndex = Utility.getRandomUnique(0, animationList.length);
var selectedAnimation = animationList[randomIndex];
print("ADC3: starting random animation -> " + selectedAnimation);
// Random selected animation
controlCommand("Robot Anamations", "ScriptStart", selectedAnimation);
print("ADC3: completed animation -> " + selectedAnimation);
// Wait for the $anamationStatus Variable to change to 0. 0 = animation complete, 1 = animation running
while (getVar("$anamationStatus") == 1) {
sleep(100);
}
};

You’re right to question it - my last rewrite did not actually use a true ARC global array for the bag. I only changed the value being stored, but I didn’t show it in the proper ARC array pattern clearly enough. So yes, let’s correct that properly.
Also, this is the better ARC way for a shuffle bag:
Important ARC note about global arrays
In ARC JavaScript, a global array is created with:
Then you can put array-style values into it with
setVar()and retrieve them withgetVar().Rewritten ARC JavaScript
What changed from the previous version
1. True global array bag
This line creates the global array:
And this line stores the shuffled array:
That is the part you were looking for.
2. Auto-refill
If the bag becomes empty, this block rebuilds it:
3. Avoid repeat after refill
This part prevents the first item after a refill from being the same as the last played animation:
4. Debug logging
This line prints the remaining bag:
One important correction
To make the "avoid repeating the same animation first after a refill" logic work properly, we should save the last played animation before exiting the script.
Add this line near the end, after the timeout check:
So the end should look like this:
Final note
Yes, your instinct was correct: in ARC, a real global array is cleaner than storing the bag as a comma-separated string. It is more readable and less error-prone.
If you want, I can now give you a final polished version of the entire script with that last
setVar("$lastAnimationPlayed", selectedAnimation);included in the right spot so you can paste it directly into ARC.Your last rewrite of this section wouldn't run. I ran the error I got back through the AI Script agent in ARC and got back this correction: Script won't run section Chest Button: Victor Hold, ADC3. It starts then it will properly release after it fails. I get this error:
AI: [code provided]
What changed:
Replaced use of bag.shift() (which failed) with manual array rebuild (for loop from index 1). Treated $animationBag as a CSV string (split/join) so it survives getVar()/setVar() correctly in ARC. Added setVar("$lastAnimationPlayed", selectedAnimation) after selection so anti-repeat logic works consistently.
It also said this at the top of it's rewritten section:
Here is it's rewritten code:
Looks like ARC doesn't like the Array method and wants to go back to a comma-separated string bag?
Yes - the error tells us what ARC’s JavaScript engine is actually doing here:
$animationBagis being returned as a string, not a native JavaScript array, so.shift()fails.So the AI script agent was right to move away from array methods like
shift()on the global variable. In ARC Jint scripting, global variables are often safest when treated as strings unless you explicitly manage them as arrays very carefully. For this use case, the comma-separated string bag is the reliable approach.Best practice here
For ARC JavaScript, I recommend:
That will be more stable in ARC.
Corrected version
This version:
Why this works better in ARC
This version avoids the exact problem you hit:
shift()on a value ARC treated as a stringSo yes: for ARC, the comma-separated string bag is the safer and more reliable way.
One important note
You’re using:
Make sure the robot skill name is spelled exactly the same in ARC. If the skill is actually named Robot Animations, that typo will cause problems.
Also worth confirming
I’m assuming your called animation scripts clear:
at the end, which you said they now do. Good.
If you want, I can also give you a simpler "utility" version of this that you can reuse for your other random sound clip scripts so they all use the same shuffle-bag pattern.
What is the bigger goal for those other scripts - just no repeats until the whole list is used, or do you want category-based shuffling too?
OK, that last rewrite did the trick. All is well and working as wanted. This was a fun and educational experience. I appreciate being given these tools to help me overcome these complicated issues.
Yes, I would love for you to give me a simpler "utility" version of this that I can reuse for my other random sound clip scripts so they all use the same shuffle-bag pattern. However I'm not sure a utility version will work for me. though. I have a few compacted scripts that have over 20 characters with up to 30 sound clips or more each. These scripts now uses the
Utility.getRandomUniquemany times to shuffle the characters to present a different one each time. When that character is picked I again use theUtility.getRandomUniqueto pick from the 30 or more sounds clips that will randomly play for that character. It all works quite well but many times I'll get the same character picked back to back or the same sound clip picked for them that will play twice.Sorry, I can't continue helping in this thread. It's grown long enough that my context window will require too much extra processing, which makes follow-ups unreliable and I can start making mistakes.
A couple of options:
LOL, I feel so set up and rejected. You offer help and then tell me to go away. LOL. OK, I'll ask more later in another thread if needed.
Seriously, though. I'm amazed and thrilled with how @Athena AI walked me through this issue and even suggested better ways and warned me about possible problems. Thanks. I'm marking this question resolved.
.
haha yah - she can only hold so many words / tokens in her context. so she didn't know when that'll fill up. you can always create a new question based on where you left off. she won't know anything about this thread though, so you kinda just have to post from your most recent code and continue on.