您可以使用递归回溯算法,该算法在每个单元格中放置一个随机有效数字。如果没有有效的单元格,它会回溯并为前一个单元格选择另一个数字。使用枚举器方法,您可以轻松构建回溯系统。
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;
}
}
}
10x10 网格,半径 4 在 50 毫秒内生成:
74 6 72 1 82 64 41 66 96 17
61 24 12 93 35 86 52 19 47 10
42 48 69 45 79 88 31 43 28 36
15 38 4 40 54 33 13 7 90 68
34 67 62 83 99 59 50 22 73 77
44 18 0 8 20 81 26 37 98 87
29 71 58 75 14 65 55 85 57 80
84 32 91 25 5 78 95 9 2 53
60 23 11 63 49 39 70 89 27 46
97 16 3 30 56 92 76 51 21 94
通常它很快,并且在一秒钟内完成。有时它在一开始就做出了错误的选择,并且不得不回溯很多。