【问题标题】:How to generate non-repeating Random Numbers in Unity如何在 Unity 中生成不重复的随机数
【发布时间】:2020-05-26 01:10:10
【问题描述】:

我正在尝试创建一个简单的宾果游戏,并希望确保宾果卡上的数字不会重复。我有一个随机数生成器,但由于某种原因,我使用的代码不起作用,因为相同的数字会不断重复。有人可以看看我下面的代码并告诉我需要修复什么或为我修复代码吗?

public Grid(int width, int height, float cellSize)
{
    this.width = width;
    this.height = height;
    this.cellSize = cellSize;

    gridArray = new int[width, height];
    debugTextArray = new TextMesh[width, height];
    for (int x = 0; x < gridArray.GetLength(0); x++)
    {
        for (int y = 0; y < gridArray.GetLength(1); y++)
        {
            debugTextArray[x, y] = UtilsClass.CreateWorldText(gridArray[x, y].ToString(), null, GetWorldPosition(x, y) + new Vector3(cellSize, cellSize) * .5f, 20, Color.white, TextAnchor.MiddleCenter);
            Debug.DrawLine(GetWorldPosition(x, y), GetWorldPosition(x, y + 1), Color.white, 100f);
            Debug.DrawLine(GetWorldPosition(x, y), GetWorldPosition(x + 1, y), Color.white, 100f);
        }
    }
    Debug.DrawLine(GetWorldPosition(0, height), GetWorldPosition(width, height), Color.white, 100f);
    Debug.DrawLine(GetWorldPosition(width, 0), GetWorldPosition(width, height), Color.white, 100f);


    for (int x = 0; x <= 4; x++)
    {
        RandomValue(0, x);
        RandomValue(1, x);
        RandomValue(2, x);
        RandomValue(3, x);
        RandomValue(4, x);
    }

}

private Vector3 GetWorldPosition(int x, int y)
{
    return new Vector3(x, y) * cellSize;
}

public void RandomValue(int x, int y)
{

    if (x >= 0 && y >= 0 && x < width && y < height)
    {
        list = new List<int>(new int[Lenght]);

        for (int j = 0; j < 25; j++)
        {

            Rand = UnityEngine.Random.Range(1, 50);


            while (list.Contains(Rand))
            {
                Rand = UnityEngine.Random.Range(1, 50);

            }

            list[j] = Rand;
            gridArray[x, y] = list[j];
        }


        debugTextArray[x, y].text = gridArray[x, y].ToString();
        debugTextArray[2, 2].text = "Free";
    }
}

【问题讨论】:

  • 您在 [1,50] 范围内生成 25 个值,因此您应该会遇到“生日问题”。没有重复的几率约为 1/300。一个简单的解决方案是将数字 1 到 50 随机排列,然后取前 25 个。

标签: unity3d random numbers


【解决方案1】:

基本上你在函数 RandomValue() 中的概念是正确的,但问题是它只检查同一列,所以你必须将 RandomValue() 的概念带到 Grid() 级别。您需要一个包含所有已批准值的列表,然后在 Grid() 处检查 Contains()。

但实际上您可以一口气完成。 确保您的宽*高不大于 maxValue。

Dictionary<Vector2Int, int> CreateBingoGrid(int width, int height, int maxValue)
{
    var grid = new Dictionary<Vector2Int, int>();
    for (int x = 0; x < width; x++)
    {
        for (int y = 0; y < height; y++)
        {
            var num = Random.Range(1, maxValue);
            while (grid.ContainsValue(num))
            {
                num = Random.Range(1, maxValue);
            }
            grid.Add(new Vector2Int(x, y), num);
        }
    }
    return grid;
}

【讨论】:

  • 这并不能解决任何问题,因为网格中的值都为零。 Dictionary CreateBingoGrid(int width, int height, int maxValue) 也是为了替代 RandomValue(int x, int y)?
  • 替换为 Grid(),它可以工作 (imgur.com/HJdlUW6),但您不能复制和粘贴。 CreateBingoGrid() 返回随机值的网格索引。然后你可以做任何你想做的事,比如 addTextMesh 等等。像这样使用它imgur.com/a/oDYAy2z
【解决方案2】:

正如对您问题的评论中提到的,最简单的方法可能是对 [1,50] 范围内的数字进行随机排列,然后取前 25 个或任意多个。

您的代码无法正常工作并且您看到很多重复的原因是因为您正在多次单独调用 RandomValue() 函数,并且您正在比较的列表变量是否已经在图表上在那个函数里面。这意味着它只会检查它在该调用中生成的值,在这种情况下只检查一行。

此外,如果您创建一个知道大小始终相同的列表,则应该使用数组来代替。列表适用于您希望大小可调整的情况。

解决方案 1:

生成数字为 1-50 的数组的一种非常简单的方法是:

//Initialize Array
int[] numbers = new int[50];
for (int i = 1; i <= numbers.Length; i++)
{
    numbers[i] = i;
}

//Shuffle Array
for (int i = 0; i < numbers.Length; i++ )
{
    int tmp = numbers[i];
    int r = Random.Range(i, numbers.Length);
    numbers[i] = numbers[r];
    numbers[r] = tmp;
}

//Get first 'n' numbers
int[] result = Array.Copy(numbers, 0, result, 0, n);
return result;

我不确定这是否是最有效的方法,但它会起作用。

解决方案 2:

要更改您的代码以检查整个列表,我会更改此部分:

for (int x = 0; x <= 4; x++)
{
    RandomValue(0, x);
    RandomValue(1, x);
    RandomValue(2, x);
    RandomValue(3, x);
    RandomValue(4, x);
}

这样的:

List<int> values = new List<int>();
for (int y = 0; y < height; y++)
{
    for (int x = 0; x < width; x++)
    {
        int r = RandomValue(1, 50);
        while (values.Contains(r))
        {
            r = RandomValue(1, 50);
        }
        values[y * width + x].Add(r);
        gridArray[x, y] = r;
    }
}

int RandomValue(int min, int max) {
    return UnityEngine.Random.Range(min, max);
}

希望这会有所帮助!

【讨论】:

  • 如何检查整个网格中的值以及如何随机排列列表并获取前 25 个值?
  • 我更新了答案并添加了一些示例。请注意,它们是针对您当前问题的两种不同解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-23
  • 2012-06-01
  • 2011-11-21
  • 1970-01-01
  • 1970-01-01
  • 2012-01-23
相关资源
最近更新 更多