英文:
Unity Infinite Loop UnityEngine.Random
问题
我正在尝试创建一个循环,以无重复数字的随机顺序输出9个数字。当我运行它时,它创建了一个无限循环,我无法找出哪里出错了。
循环无限的原因是您在内部循环(j 循环)中使用了 j--,这可能导致循环控制混乱。建议修改逻辑以确保正确退出内部循环。
<details>
<summary>英文:</summary>
I'm trying to create a loop that outputs 9 numbers in a random order with no repeating numbers. When I run it it creates an infinite loop and I can't figure out where I went wrong.
public void randomizer()
{
resetArray();
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
int randomNumber = UnityEngine.Random.Range(1, 9);
if(!numCheck(randomNumber))
{
buttons[i, j] = randomNumber;
}
else
{
j--;
}
Debug.Log(randomNumber);
}
}
}
public void resetArray()
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
buttons[i,j] = 0;
}
}
}
public bool numCheck(int num)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (buttons[i, j] == num)
{
return true;
}
}
}
return false;
}
The code loops infinitely, however when my friend mimic'd it in c# it worked fine on his end. What is causing the infinite loop?
</details>
# 答案1
**得分**: 3
以下是翻译好的部分:
"Looping to ensure that the current random number hasn't already been generated is never going to be a good way of doing things. The problem is that as you approach 'all numbers generated', the more collisions (an already-used number being generated) you encounter. You essentially need to loop more and more towards the end.
For a finite set of numbers, it's generally better to use something like the [Fisher-Yates shuffle](https://stackoverflow.com/questions/56378647/fisher-yates-shuffle-in-c-sharp) on an existing set of numbers. I'll provide an example with your specific problem using vanilla C#, though you can easily convert this to Unity's Random class.
First we'll generate an array of numbers 1-9, and then we'll shuffle them."
```cs
var random = new Random();
// Fill the array with numbers 1-9
int [] numbers = new int[9];
for (int i = 0; i < numbers.Length; ++i)
{
numbers[i] = (i + 1);
}
// the above is equivalent to int [] numbers = Enumerable.Range(1, 9).ToArray();
Console.WriteLine(string.Join(", ", numbers));
// Shuffle the array
for (int i = 0; i < numbers.Length - 1; ++i)
{
int pos = random.Next(i, numbers.Length);
int tmp = numbers[pos];
numbers[pos] = numbers[i];
numbers[i] = tmp;
}
Console.WriteLine(string.Join(", ", numbers));
当我运行它时,第一个 WriteLine 打印出 1, 2, 3, 4, 5, 6, 7, 8, 9,这是我们期望的,但第二行打印出 8, 2, 1, 7, 9, 4, 6, 3, 5,表示我们的洗牌成功。
现在我们可以使用这些数据来填充我们的二维数组。
int[,] buttons = new int[3, 3];
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
// i * 3 + j basically divides the numbers array into
// 3 3-digit sections, and then chooses the number
// at position j from the section referenced by i
buttons[i, j] = numbers[i * 3 + j];
}
}
// the above is equivalent to Buffer.BlockCopy(numbers, 0, buttons, 0, 9 * sizeof(int));
我们可以使用以下代码验证数组是否正确填充了每个位置:
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
if (j != 0)
{
Console.Write(", ");
}
Console.Write(buttons[i, j]);
}
Console.WriteLine();
}
作为一个简短的版本,我们可以编写以下内容(在这里我还替换了Unity的随机方法):
// Generate an array with numbers 1-9
int [] numbers = Enumerable.Range(1, 9).ToArray();
// Shuffle the array
for (int i = 0; i < numbers.Length - 1; ++i)
{
int pos = UnityEngine.Random.Range(i, numbers.Length);
int tmp = numbers[pos];
numbers[pos] = numbers[i];
numbers[i] = tmp;
}
// Populate the 2D buttons array with the values in the 1D number sarray
Buffer.BlockCopy(numbers, 0, buttons, 0, 9 * sizeof(int));
英文:
Looping to ensure that the current random number hasn't already been generated is never going to be a good way of doing things. The problem is that as you approach "all numbers generated", the more collisions (an already-used number being generated) you encounter. You essentially need to loop more and more towards the end.
For a finite set of numbers, it's generally better to use something like the Fisher-Yates shuffle on an existing set of numbers. I'll provide an example with your specific problem using vanilla C#, though you can easily convert this to Unity's Random class.
First we'll generate an array of numbers 1-9, and then we'll shuffle them.
var random = new Random();
// Fill the array with numbers 1-9
int [] numbers = new int[9];
for (int i = 0; i < numbers.Length; ++i)
{
numbers[i] = (i + 1);
}
// the above is equivalent to int [] numbers = Enumerable.Range(1, 9).ToArray();
Console.WriteLine(string.Join(", ", numbers));
// Shuffle the array
for (int i = 0; i < numbers.Length - 1; ++i)
{
int pos = random.Next(i, numbers.Length);
int tmp = numbers[pos];
numbers[pos] = numbers[i];
numbers[i] = tmp;
}
Console.WriteLine(string.Join(", ", numbers));
When I ran it, the first WriteLine prints 1, 2, 3, 4, 5, 6, 7, 8, 9 as we expect, but the second line printed WriteLine printed 8, 2, 1, 7, 9, 4, 6, 3, 5, indicating that our shuffle was successful.
Now we can use this data to populate our 2D array.
int[,] buttons = new int[3, 3];
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
// i * 3 + j basically divides the numbers array into
// 3 3-digit sections, and then chooses the number
// at position j from the section referenced by i
buttons[i, j] = numbers[i * 3 + j];
}
}
// the above is equivalent to Buffer.BlockCopy(numbers, 0, buttons, 0, 9 * sizeof(int));
We can verify that the array has been populated correctly using this code to write each position:
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
if (j != 0)
{
Console.Write(", ");
}
Console.Write(buttons[i, j]);
}
Console.WriteLine();
}
As a short version, we could write the following (I've also substituted the Unity random method here):
// Generate an array with numbers 1-9
int [] numbers = Enumerable.Range(1, 9).ToArray();
// Shuffle the array
for (int i = 0; i < numbers.Length - 1; ++i)
{
int pos = UnityEngine.Random.Range(i, numbers.Length);
int tmp = numbers[pos];
numbers[pos] = numbers[i];
numbers[i] = tmp;
}
// Populate the 2D buttons array with the values in the 1D number sarray
Buffer.BlockCopy(numbers, 0, buttons, 0, 9 * sizeof(int));
答案2
得分: 1
请按照ProgrammingLlama的优秀回答,以下是一个稍微简化的方法,可能对你有用:
public int[,] Randomizer()
{
int[] shuffled =
Enumerable
.Range(1, 9)
.OrderBy(x => Random.Shared.Next())
.ToArray();
int[,] output = new int[3, 3];
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
output[i, j] = shuffled[i * 3 + j];
return output;
}
你只需要使用 `buttons = Randomizer();` 调用它。
英文:
Please go with ProgrammingLlama's excellent answer, but here is a slightly more simplified approach that might be useful to you:
public int[,] Randomizer()
{
int[] shuffled =
Enumerable
.Range(1, 9)
.OrderBy(x => Random.Shared.Next())
.ToArray();
int[,] output = new int[3, 3];
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
output[i, j] = shuffled[i * 3 + j];
return output;
}
You'd just go ahead and call that with buttons = Randomizer();.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论