Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何创建一个半随机的数字网格,使每个数字只出现一次,最重要的是不太接近其前序数字?_C#_Algorithm_Math_Random_Grid - Fatal编程技术网

C# 如何创建一个半随机的数字网格,使每个数字只出现一次,最重要的是不太接近其前序数字?

C# 如何创建一个半随机的数字网格,使每个数字只出现一次,最重要的是不太接近其前序数字?,c#,algorithm,math,random,grid,C#,Algorithm,Math,Random,Grid,假设我有一个网格(10x10),我想用数字序列0-99填充它。以下是一些条件: 序列中的每个数字在网格中只能出现一次 每个数字(从序列中)的位置应该是随机的(x,y坐标) 序列中的后续数字(例如5和6)不能出现在彼此相邻(或半径范围内)的网格中 我可以处理条件1和2,没问题。条件3(对我来说)更难。我使用蛮力填充网格,但这有几个问题。首先,当网格较大(100x100)时,速度较慢。其次(也是最重要的),暴力并不保证解决方案(例如,序列中的最后两个数字将彼此相邻,因此不允许->无解决方案) 如果有

假设我有一个网格(10x10),我想用数字序列0-99填充它。以下是一些条件:

  • 序列中的每个数字在网格中只能出现一次
  • 每个数字(从序列中)的位置应该是随机的(x,y坐标)
  • 序列中的后续数字(例如5和6)不能出现在彼此相邻(或半径范围内)的网格中
  • 我可以处理条件1和2,没问题。条件3(对我来说)更难。我使用蛮力填充网格,但这有几个问题。首先,当网格较大(100x100)时,速度较慢。其次(也是最重要的),暴力并不保证解决方案(例如,序列中的最后两个数字将彼此相邻,因此不允许->无解决方案)

    如果有人能帮我一个合适的算法(甚至一些数学/逻辑资源),这将是有帮助的。如果您可以提供解决方案,理想情况下,条件3应该是可定义的(即,用户/编码器确定相邻数字不能出现的半径)。最后,不存在环绕问题(即,如果数字5出现在行的最后一列中,那么6可以出现在下一行的第一列中)

    很多话,但我认为这是一个非常酷的问题,因为现实世界需要(“神经元的随机”光激发)

    提前感谢你的帮助

    皮特

    这里有一个想法:

    对于
    NxN
    网格,生成一个数字列表
    0..NxN-1
    ,然后将其洗牌(Fisher-Yates或其他)

    然后,填写网格:对于每个单元格,在无序列表中选择第一个元素,该元素将根据您的规则和网格的当前状态进行调整。将每个元素移动到网格时,将其从无序列表中移除

    如果由于无序列表中没有剩余的有效数字而无法填充网格单元格,请在填充的网格单元格中搜索,直到找到一个单元格,该单元格中的数字在此处有效,而无序列表中剩余的一个数字在此处也有效。然后移动到此处,并将有效号码从列表中移动到此处


    我不确定你是否可能找不到这样一个数字,除非你的半径设置得太高,任何解决方案都不存在。读者练习;)

    这听起来像是我用来为游戏生成星域的算法。我在笛卡尔平面上布置了一个给定维度的星系和所需数量的恒星。恒星不可能占据同一个位置,也不可能以n个单位相互存在。我偷了一些东西,但这应该有用

            for (int i = 0; i < u.StarCount; i++)
            {
                bool badStar = true;  //Assume failure
                do
                {
                    //Create a star, get a random location, and where the rarity of its spectral type
                    StellarBody sb = new StellarBody();
                    sb.PositionX = r.Next(0, u.width);
                    sb.PositionY = r.Next(0, u.height);
                    int randomAbundance = r.Next(maxAbundance);
    
                    //Test the location against previous stars added, disallow positions where the centers are within 8 units of one another
                    if (!u.StellarBodies.Any(p => Math.Abs(p.PositionX.Value - sb.PositionX.Value) < minGap && Math.Abs(p.PositionY.Value - sb.PositionY.Value) < minGap))
                    {
                        //Get the spectral types based on the abundance value of the spectral types compared to the random abundance number
                        List<Models.StellarClass> abundanceTypes = starTypes.FindAll(f => f.Abundance == starTypes.Where(p => p.Abundance > randomAbundance).Min(m => m.Abundance));
    
                        try
                        {
                            int index = r.Next(0, abundanceTypes.Count());
                            sb.StellarClassID = abundanceTypes[index].StellarClassID;                            
                            sb.CatalogDesignation = index.ToString() + u.StellarBodies.Count.ToString()
                                                    + abundanceTypes[index].Code + "-" + CoordinateMath.GetMortonNumber((int)sb.PositionX, (int)sb.PositionY).ToString();
    
                            minOrbit = abundanceTypes[index].MinOrbitZone;
                            maxOrbit = abundanceTypes[index].MaxOrbitZone;
                        }
                        catch (Exception ex)
                        {
                            sb.StellarClassID = starTypes.First(p => p.Code.Equals("Dork", StringComparison.CurrentCultureIgnoreCase)).StellarClassID;
                        }
    
    
                        u.StellarBodies.Add(sb);
                        badStar = false;
                    }
                } while (badStar);
            }
    
    for(int i=0;iMath.Abs(p.PositionX.Value-sb.PositionX.Value)f.funsity==starTypes.Where(p=>p.funsity>randomFunsity).Min(m=>m.funsity));
    尝试
    {
    int index=r.Next(0,abundantypes.Count());
    sb.StellarClassID=丰度类型[索引].StellarClassID;
    sb.catalogsignation=index.ToString()+u.StellarBodies.Count.ToString()
    +丰富类型[索引]。代码+“-”+坐标Math.GetMortonNumber((int)sb.PositionX,(int)sb.PositionY).ToString();
    米诺比=丰度类型[索引]。米诺比酮;
    maxOrbit=丰度类型[索引].MaxOrbitZone;
    }
    捕获(例外情况除外)
    {
    sb.StellarClassID=starTypes.First(p=>p.Code.Equals(“Dork”,StringComparison.CurrentCultureIgnoreCase)).StellarClassID;
    }
    u、 加上(某人);
    坏星=假;
    }
    }while(badStar);
    }
    
    您可以使用递归回溯算法,在每个单元格中放入一个随机有效数字。如果没有有效的单元格,它将回溯并为上一个单元格拾取另一个数字。使用枚举器方法,可以轻松构建回溯系统

    class Generator
    {
        public int Width { get; private set; }
        public int Height { get; private set; }
        public int Radius { get; private set; }
    
        private List<int> _numbers;
        private bool[] _picked;
        private int[] _grid;
        private Random _rnd;
    
        public Generator(int width, int height, int radius)
        {
            Width = width;
            Height = height;
            Radius = radius;
    
            _rnd = new Random();
            _numbers = Enumerable.Range(0,Width*Height).OrderBy(_ => _rnd.Next()).ToList();
            _picked = _numbers.Select(n => false).ToArray();
            _grid = new int[width*height];
        }
    
        public int[] Generate()
        {
            return Generate(0)
                .Select(a => a.ToArray()) // copy
                .FirstOrDefault();
        }
    
        private IEnumerable<int[]> Generate(int index)
        {
            if (index >= Width * Height)
            {
                yield return _grid;
                yield break;
            }
    
            int xmid = index%Width;
            int xlow = Math.Max(0, xmid - Radius);
            int xhigh = Math.Min(xmid + Radius, Width - 1);
            int ymid = index/Width;
            int ylow = Math.Max(0, ymid - Radius);
            int yhigh = ymid;
    
            var validNumbers = _numbers
                .Where(n =>
                    !_picked[n] &&
                    Enumerable.Range(xlow, xhigh - xlow + 1).All(x =>
                        Enumerable.Range(ylow, yhigh-ylow+1).All(y =>
                            y*Width + x >= index // Not generated yet
                            || Math.Abs(x - xmid) + Math.Abs(y - ymid) > Radius // Outside radius
                            || Math.Abs(_grid[y*Width+x] - n) > 1 // Out of range
                        )
                    )
                )
                .ToList();
    
            foreach (var n in validNumbers)
            {
                _grid[index] = n;
                _picked[n] = true;
                foreach (var sol in Generate(index + 1))
                {
                    yield return sol;
                }
                _picked[n] = false;
            }
        }
    }
    

    它通常很快,在一秒钟内完成。有时,它在开始时做出了错误的选择,并且必须进行多次回溯。

    我会快速填充网格(尽量避免结块,但不要太用力)。当网格被填充时,我会找到聚集的数字并将它们四处移动。不涉及回溯。这种方法对于非常大的网格应该非常有效

    第一阶段的伪代码:

    int N = 100;
    int minDistance = 10;
    int maxCollisionCount = 5;
    int saturationThreshold = N * N * 0.85;
    
    grid[0,0] = 1;
    int oldX = 0, oldY = 0;
    int newX, newY;
    
    for (i = 2; i <= N * N; i++)
    {
        bool foundNewCell = false;
    
        for (collisionCount = 0; collisionCount < maxCollisionCount; collisionCount++)
        {
            newX = rnd(0, N - minDistance);
            if (newX >= oldX - minDistance / 2)
                newX += minDistance;
    
            newY = rnd(0, N - minDistance);
            if (newY >= oldY - minDistance / 2)
                newY += minDistance;
    
            if (grid[newX, newY] == 0)
            {
                grid[oldX = newX, oldY = newY] = i;
                foundNewCell = true;
                break;
            }
    
            if (i > saturationThreshold)
                break;
        }
    
        if (foundNewCell)
            continue;
    
        // Find newX and newY by some other way, even if there would be clumping.
        // For instance use already randomed newX and newY and circle around until
        // you find an empty cell
        ...
    
        grid[oldX = newX, oldY = newY] = i;
    }
    
    int N=100;
    智力距离=10;
    int maxCollisionCount=5;
    int饱和阈值=N*N*0.85;
    网格[0,0]=1;
    int oldX=0,oldY=0;
    int newX,newY;
    对于(i=2;i=oldX-minDistance/2)
    newX+=思维距离;
    newY=rnd(0,N-思维距离);
    if(newY>=oldY-minDistance/2)
    新奇+=思维距离;
    if(网格[newX,newY]==0)
    {
    网格[oldX=newX]
    
    int N = 100;
    int minDistance = 10;
    int maxCollisionCount = 5;
    int saturationThreshold = N * N * 0.85;
    
    grid[0,0] = 1;
    int oldX = 0, oldY = 0;
    int newX, newY;
    
    for (i = 2; i <= N * N; i++)
    {
        bool foundNewCell = false;
    
        for (collisionCount = 0; collisionCount < maxCollisionCount; collisionCount++)
        {
            newX = rnd(0, N - minDistance);
            if (newX >= oldX - minDistance / 2)
                newX += minDistance;
    
            newY = rnd(0, N - minDistance);
            if (newY >= oldY - minDistance / 2)
                newY += minDistance;
    
            if (grid[newX, newY] == 0)
            {
                grid[oldX = newX, oldY = newY] = i;
                foundNewCell = true;
                break;
            }
    
            if (i > saturationThreshold)
                break;
        }
    
        if (foundNewCell)
            continue;
    
        // Find newX and newY by some other way, even if there would be clumping.
        // For instance use already randomed newX and newY and circle around until
        // you find an empty cell
        ...
    
        grid[oldX = newX, oldY = newY] = i;
    }