Unity 无限循环 UnityEngine.Random

huangapple go评论93阅读模式
英文:

Unity Infinite Loop UnityEngine.Random

问题

我正在尝试创建一个循环,以无重复数字的随机顺序输出9个数字。当我运行它时,它创建了一个无限循环,我无法找出哪里出错了。

循环无限的原因是您在内部循环(j 循环)中使用了 j--,这可能导致循环控制混乱。建议修改逻辑以确保正确退出内部循环。


<details>
<summary>英文:</summary>

I&#39;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&#39;t figure out where I went wrong.

public void randomizer()
{
    resetArray();
    for (int i = 0; i &lt; 3; i++)
    {
        for (int j = 0; j &lt; 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 &lt; 3; i++)
    {
        for (int j = 0; j &lt; 3; j++)
        {
            buttons[i,j] = 0;

        }
    }
}

public bool numCheck(int num)
{
    for (int i = 0; i &lt; 3; i++)
    {
        for (int j = 0; j &lt; 3; j++)
        {
            if (buttons[i, j] == num)
            {
                return true;
            }

        }
    }
    return false;
}


The code loops infinitely, however when my friend mimic&#39;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 &lt; 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 &lt; 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 &lt; 3; ++i)
{
    for (int j = 0; j &lt; 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 &lt; 3; ++i)
{
    for (int j = 0; j &lt; 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 &lt; 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 &lt; numbers.Length; ++i)
{
    numbers[i] = (i + 1);
}
// the above is equivalent to int [] numbers = Enumerable.Range(1, 9).ToArray();

Console.WriteLine(string.Join(&quot;, &quot;, numbers));

// Shuffle the array
for (int i = 0; i &lt; 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(&quot;, &quot;, 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 &lt; 3; ++i)
{
    for (int j = 0; j &lt; 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 &lt; 3; ++i)
{
    for (int j = 0; j &lt; 3; ++j)
    {
        if (j != 0)
        {
            Console.Write(&quot;, &quot;);
        }
        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 &lt; 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 =&gt; Random.Shared.Next())
			.ToArray();
	
	int[,] output = new int[3, 3]; 
	
	for (int i = 0; i &lt; 3; i++)
		for (int j = 0; j &lt; 3; j++)
			output[i, j] = shuffled[i * 3 + j];
			
	return output;
}

You'd just go ahead and call that with buttons = Randomizer();.

huangapple
  • 本文由 发表于 2023年5月10日 11:04:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76214621.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定