英文:
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();
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论