A Way to Pick Unique Random Values?

I’m trying to make the game randomly pick one from five elements inside a Enum list. Then when the event is fired again, it will check if that element was already picked in previous attempt.

If the element was picked, it would try again, a continue until it finds one it hasn’t picked yet.

This is what I tried.
This is inside a widget blueprint.

On launch, it would randomly pick an Enemy Element from the Enum list. Then check the Contains if EnemyElementUsed array has the same value as Enemy Element. The array is empty by default. If False, it would add the to the EnemyElementUsed array.

On second launch, it sets a new random element, checks the Contain. Now if what was added from the previous launch matches the EnemyElementUsed array, it’s supposed to loop.

But it’s not really working out.

Some other notes, if it helps error checking:
The game compares Enemy and Player Elements using the same Enum list, but from different blueprints and Variable set ups. This hasn’t caused any changes into player selected element, but I don’t know if it plays a role.

I’m trying to make the game randomly
pick one from five elements inside a
Enum list. Then when the event is
fired again, it will check if that
element was already picked in previous
attempt.

If the element was picked, it would try again, a continue until it finds one it hasn’t picked yet.

Depending on how complex the final system is supposed to be, I’d lean towards the following solution as it’s not prone to indexing errors and there’s no need for any iteration or looping whatsoever:

  • create an All Enums array
  • pick one element and add it to the Final Array
  • remove the picked element from All Enums
  • rinse and repeat

That’s pretty much it, it’s like having 2 buckets and pouring contents from one into another.

I think this is what you’re after.


Some other elements that may be useful here, again depends how deep the rabbit hole goes:

  • Add Unique node: it automatically checks whether the array already contains the value and does not add it if True, and it’s kind enough to return a bool

  • Sets: the keys on the list must be unique so it’s a perfect container for what you’re doing

Hey, thanks again.

Though, it doesn’t look like this worked. It’s still picking the same elements on future choices.
Sometimes on next turn as well.

This is how I’ve set it up.

I added a Set Enumerator, since I needed the reference.

As far as I understood it. It looks like I’m trying to check if the EnemyElementList is not 0. And if True, it would pick a random index, and add it to the UsedElement Enum Array, then remove that index from EnemyElementList.
I have also set that index as EnemyElement Enum, which seems to work just fine, during testing.

It should work in theory, but it does’t look like it even removed the index to begin with.
Removing index means taking it out of the list, making it impossible to pick it again from that list, yes?

What I didn’t quite understand was the part of adding an element to the FinalArray, and removing it from EnemyElementList. Wouldn’t that ensure that one element would never be picked on the first turn?

How does your Enemy Element List array look like? It has to have unique items, have a look at my pic, the array is fully visible there.

Also, where you Print, it does not really show you that it has been used, it just shows that you’ve emptied the array and there’s nothing more to add. Not important here but you may need this info.

278668-cardpick3.png

And the UsedElement is empty when we start? If it’s not empty, use AddUnique instead of Add.

Ah sorry, I renamed UsedElement back to FinalArray.

It basically contains index 0: Fire.

I gave it another go and the script I posted works flawlessly. Used AddUnique instead and added an element to the FinalArray just to replicate your workflow.

What is the duplicate that you’re seeing?

Here’s a log; 9 iterations and the final array contains 9 elements, all unique, and the initial element 0 is also accounted for. Each iteration adds something unique at the end.

Here’s how I print the content:

Ah I see, there is a miscommunication on my request.

I want the game to pick a unique element the next time the event is fired.

Say, on turn 1, the game picks Fire element. The next turn, the event is fired again, Fire element is disabled until I restart the game.

What you offered, is certainly a random unique generator. Just, for single turns.

Say, on turn 1, the game picks Fire
element. The next turn, the event is
fired again, Fire element is disabled
until I restart the game.

So it’s even much simpler then:

Check if the All Enums array Contains what you’re looking for, if it does, remove it. Next time you check with Contains, it either will have it (has not been used) or will not have it (has been used)

Ah yes, this works quite simply. And I also now understand why my previous attempts weren’t working.

As mentioned, the code is inside a widget with “Yes” prompt. It looks like every time I hide the widget and recalls it, the array is resets, and the list is filled again. So it would always be able to pick used elements.

It looks like every time I hide the
widget and recalls it, the array is
resets, and the list is filled again

This should not be happening, are your sure you’re not letting the Garbage Collector remove it from memory and create a new one?

Can you show the widget hiding / recalling logic?

Ah, I don’t think I know what this Garbage Collector is.

The first image is when it’s calling the widget.

The second image is when I hide the widget. Both “Yes” and “No” buttons uses the same setup. Though, “No” wouldn’t pick an element to begin with.

How do you show the widget again then?

It would just run this again.

278685-cardpick5.png

Yup, this will create a brand new widget and cause a memory leak, too: you create an object, hide it, then you create another one, hide it, then another… You get the idea.

These are separate instances of the widget, each with their own variables and functionality. Since you want yours to hold and handle persistent data, you need to use the same widget again.


Instead, right click the the Return Value of the Create Widget node and promote it to variable. This is your widget reference. Next time you want to do something with a widget, use its reference. You can even automate widget creation like so:

If you run this for the first time, the reference is Invalid, so it will create a new widget, fill the reference, and add the widget to the viewport. If you run it again, the reference IS Valid so you can show / hide the widget it points at.

This method is useful when you switch levels (which wipes the widgets) and you do not always want to remember to manually recreate all widgets.

Oh dearest, that makes sense. That is so logical.

Ah, what is this about Garbage Collector, though?

Ah, what is this about Garbage
Collector, though?

To put it it simply, it’s a system that removes objects from memory when they are no longer in use. It’s mostly fully automatic and you generally do not need to do anything about it; for example - when you call Destroy on the object. The memory it used to occupy will be (eventually) freed up.

More info:
https://wiki.unrealengine.com/Garbage_Collection_Overview


You were adding widgets and hiding them without referencing; when you created another new widget, the old one was already being eaten by the GC (best case scenario) since it had no valid reference. Technically, that’s a good thing! But you were unable to access the old widget anymore.