- Home /
Trying to solve an issue with a while loop to search to see if numbers are the same. Will explain in description.
I'm going to try to explain this the least confusing way possible.
In previous methods I created the array - pieces[]. I added gameObjects according to their tag to the array.
Below I have the script that is causing the problem. I know what is causing the problem. In my while loop I have || usedNumbers.Contains(iter)). When I added this, it caused an infinite loop. Otherwise, the code works great.
Well the idea that I was looking for was -1- that a number could not be repeated, -2- that an object couldn't assign itself its own number, or -3- an object could not be assigned a number of a gameObject if it's number was assigned there already. 3 is a mouthful but that is what I am looking to fix.
"I am gameObject 3, number 1 has been assigned to me, but gameObject 1 has already been assigned number 3, so I need to repeat the loop."
while( usedNumbers.Contains( newNumber ) || newNumber == iter || usedNumbers.Contains(iter))
If I could find an alternate solution to this, that would be awesome. I was wondering about making a list of the iterations that had already been ran and do it about the same as I did with usedNumbers. I will do that now as I wait for a reply. I bet it's something easy that I am just overlooking.
Edit: I tried writing the new list the same as my previous, but adding the current iter to it and it was still an infinite loop. usedNumbers.Contains(iter) I still think this should work and not cause an infinite.
void AssignChildren ()
{
int pieceCount = pieces.Length;
List<int> usedNumbers = new List<int>();
int newNumber;
for (int iter = 0; iter < pieceCount; iter++)
{
newNumber = Random.Range (0, pieceCount);
while( usedNumbers.Contains( newNumber ) || newNumber == iter || usedNumbers.Contains(iter))
{
newNumber = Random.Range( 0, pieceCount);
}
PieceScript assignPieceChild = pieces [iter].GetComponent<PieceScript> ();
assignPieceChild.whoDoIControl = newNumber;
usedNumbers.Add( newNumber );
}
}
Answer awaiting moderation. (Copied and pasted here) I would ins$$anonymous$$d initialize a list of unused numbers, and remove them from the list as they get assigned. That way, there is no need to double check the number as you are assigning them. See code below :)
void AssignChildren()
{
List<int> unusedNumbers = new List<int>();
int i = 0;
while (i < pieces.Count)
{
unusedNumbers.Add(i);
}
int newNumber;
for (int iter = 0; iter < pieces.Count; iter++)
{
PieceScript assignPieceChild = pieces[iter].GetComponent<PieceScript>();
int selectedIndex = -1;
GameObject query = new GameObject();
do
{
selectedIndex = Random.Range(0, unusedNumbers.Count - 1);
query = (from x in pieces
where x.GetComponent<PieceScript>().whoDoIControl == unusedNumbers[selectedIndex]
select x).FirstOrDefault();
} while (selectedIndex == -1 || query != null);
newNumber = unusedNumbers[selectedIndex];
unusedNumbers.Remove(unusedNumbers[selectedIndex]);
assignPieceChild.whoDoIControl = newNumber;
}
}
But my problem is that I don't want objectA to be the parent of objectB while objectB is the parent of objectA. If objectA is parented to objectB, then the loop needs to repeat to avoid them being parented to each other and causing issues. I'm not actually parenting them, but it's the idea behind it that I am looking for.
Doing this could lead to a circle of parenting such as objectA parents B; objectB parents C; objectC parents A. Which is something that I want the possibility of rather than the above.
@Ownedbycow I think I understand what you're looking for now. Please see the updated script. You will need to add using System.Linq
to use the code.
Also, I suspect you can do away with the selectedIndex == -1
option in the while brackets.
The potential problem is that you may end up with the last element not having a element that fulfills that condition to be assigned to.
Yes, it's definitely stuck in an infinite loop where you would think it is:
while( usedNumbers.Contains( newNumber ) || newNumber == iter || usedNumbers.Contains(iter))
Specifically:
usedNumbers.Contains(iter)
You generate a random number, which will likely be a greater number than your current iterator. For example, you're on the 3rd (2) pass and generate a 50. Now, when you get to the 51st pass (50), element 2 still contains the number 50, so usedNumbers.Contains(50)
will be true, no matter what you change the value of newNumber to.
Answer by Eno-Khaon · Apr 29, 2017 at 05:20 AM
Hmm... this all seems too expensive to calculate, so why not try a linear approach? The cost is directly tied to the number of pieces you're assigning values to.
First, you'll generate the numbers and distribute them. Then, the second pass will sanitize everything in case of duplicates.
void AssignChildren()
{
// The total count of pieces
int pieceCount = pieces.Length;
// The remaining count in the list
int remaining = pieceCount;
// The list to be filled initially
List<int> availableNumbers = new List<int>();
// The array to fill for the finalized set
int[] usedNumbers = new int[pieceCount];
// Populate the list with one of every number
for(int i = 0; i < pieceCount; i++)
{
availableNumbers.Add(i);
}
for(int i = 0; i < pieceCount; i++)
{
// Generate a random number between 0 and the remaining quantity in the List, then remove that value from the list
int randomSelection = Random.Range(0, remaining);
usedNumbers[i] = availableNumbers[randomSelection];
availableNumbers.RemoveAt(randomSelection);
remaining--;
}
for(int i = 0; i < pieceCount; i++)
{
// Check for numbers matching their position
if(usedNumbers[i] == i)
{
// Swap the value for any other one, and neither can be itself anymore
int newRandom = Random.Range(0, pieceCount - 1);
if(newRandom >= i)
{
newRandom = newRandom++;
}
Swap(ref usedNumbers[i], ref usedNumbers[newRandom]);
}
}
for(int i = 0; i < pieceCount; i++)
{
// Populate the list with the corrected values
PieceScript assignPieceChild = pieces[i].GetComponent<PieceScript>();
assignPieceChild.whoDoIControl = usedNumbers[i];
}
}
void Swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
Edit: Whoops, forgot to update my post with something I'd tested in Unity at the time... generating random numbers is much more useful when they're actually used.
Your answer
Follow this Question
Related Questions
Spawning objects in infinite scroller game 0 Answers
Random.range multiple instantiations without repetition 1 Answer
How to repeat a random result 3 Answers
audioclip repeat randomly -1 Answers