在二维空间中,我需要创建一种特殊的泛洪填充方法,该方法将根据一组预定义对象(下图中的红色,蓝色,绿色和黄色对象)生成随机数组。
edit:任何单个“填充对象”都不应与另一个对象重叠,并且它们的放置应该看起来是随机的,但是可以为每个对象添加某种形式的出现概率是可以的。甚至可能将红色1x1以外的所有对象放到满足一定容量的位置,然后用红色填充其余的对象。
现在想象一个随机结果,该结果如下所示。
edit:我提供的结果图像显示,所有内容始终都用红色方块分隔开,这当然是可能的,但不是范围的必要部分。我以这种方式绘制图像是为了消除任何观念,即红色以外的某些颜色对象被认为可与其他类似颜色的对象“连接”在一起。换句话说,我不希望人们认为3x3的绿色对象可以成为6x3的算法。应该将其视为随机分开放置的两个单独的3x3。为了解决@jdweng的评论,部分解决方案很可能需要在FillObject类中添加某种形式的出现概率字段,然后始终将1x1红色正方形视为构成空间的对象。
这是我到目前为止提出的代码。我很难过这个,直到最后。我熟悉标准的洪水填充,但不确定如何使用随机大小的“填充对象”。
//Defined objects that make up the grid fill
public class FillObject
{
public int xDim { get; set; }
public int yDim { get; set; }
public string color { get; set; }
public FillObject(int x, int y, string c)
{
xDim = x;
yDim = y;
color = c;
}
}
//container for information about a position on the grid
public class GridPosition
{
public int xPosition { get; set; }
public int yPosition { get; set; }
public string color { get; set; }
}
public class GridGenerator
{
//declare the intitial possible fill objects
public static FillObject[] fillObjects = new FillObject[]
{
new FillObject(1, 1, "red"),
new FillObject(2, 2, "blue"),
new FillObject(3, 3, "green"),
new FillObject(4, 4, "yellow")
};
//Generic list of grid positions
public List<GridPosition> grid = new List<GridPosition>();
//Method to generate random grid filled with the fill objects
public void GenerateGrid(int startX, int startY, int endX, int endY)
{
//Iterate through grid and set each "cell" to a color based on the original fill objects
for(int x = startX; x <= endX; x += 1)
{
for(int y = startY; y <= endY; y += 1)
{
grid.Add(new GridPosition());
}
}
}
}
我考虑过只是遍历for循环并测试已创建位置的列表,然后利用随机机会“填充”填充对象(如果它们合适),但是在每个循环中测试列表似乎效率不高进行迭代,以找到填充位置的存在,然后测试每个对象的偏移量也会出现问题。可能是一种递归方法,该方法以最大的“ fillObject”开头,然后递归地进行测试和填充,但同样看起来非常麻烦。是否有一些聪明的方法可以在我看不到的网格循环中执行此操作?
编辑:这是明确的目标
创建一个方法,该方法生成一个List对象,该对象 包含网格上的每个位置。
每个网格位置应包含如下位置:int x和int y GridPosition类中的字段。
生成的GridPosition对象应遵循原始的
FillObject结构。
每个对象的出现概率都很好,一切都
剩下的可以用红色的1x1对象填充。
相同颜色的对象可以相邻(即使结果
图片未显示此内容)
理想情况下,这是一次完成的操作(例如洪水填充),但是
递归是另一种可能性。
真正的随机性不是必需的,只需要看起来有些
随机,但也不应出现图案。
答案 0 :(得分:1)
好吧,今天早上我有一个免费的小时,所以我对此感到一阵刺痛。为了快速起见,我使用了unsafe
,fixed
和指针。我不确定您是否需要图像,但是它也可以与多维数组一起使用。
FillObject
public class FillObject
{
public FillObject(int width, Color color)
{
Width = width;
Color = color.ToArgb();
}
public int Color { get; set; }
public int Width { get; set; }
}
扩展方法
public static class Extensions
{
public static Color NextColor(this Random r) => Color.FromArgb(r.Next(256), r.Next(256), r.Next(256));
public static FillObject GetObject(this List<FillObject> objects, int maxSize, Random rand)
{
var nextObjs = objects.Where(o => o.Width <= maxSize)
.ToList();
return nextObjs[rand.Next(nextObjs.Count)];
}
}
帮助方法
public static unsafe bool GetMaxSize(int x, int y, Size size, int* array, int pad, out int maxSize)
{
maxSize = 0;
//we cant be within pad distance of anything else or the edges
for (var y2 = y - pad; y2 < y + pad; y2++)
for (var x2 = x - pad; x2 < x + pad; x2++)
if (y2 < 0 || x2 < 0 || y2 >= size.Height || x2 >= size.Width || *(array + x2 + y2 * size.Width) != 0)
return false;
// so what do we have left
for (var y2 = y - pad; y2 < y + 1; y2++)
{
var max = maxSize > 0 ? maxSize : _largest + pad;
maxSize = 0;
for (var x2 = x; x2 < size.Width && x2 < x + max; x2++, maxSize++)
if (*(array + x2 + y2 * size.Width) != 0)
break;
}
// safety first
maxSize = Math.Min(maxSize - pad, Math.Min(size.Width - x - pad, size.Height - y - pad));
return maxSize > 0;
}
主要方法
public static unsafe void Generate(Size size, int* array, int pad)
{
for (var y = 0 + pad; y < size.Height; y++)
for (var x = 0 + pad; x < size.Width; x++)
{
// no maxSize bail
if (!GetMaxSize(x, y, size, array, pad, out var maxSize))
continue;
// pick a random one
var nextObj = _objects.GetObject(maxSize, _rand);
// draw the thing
for (var y2 = y; y2 < y + nextObj.Width; y2++)
for (var x2 = x; x2 < x + nextObj.Width; x2++)
*(array + x2 + y2 * size.Width) = nextObj.Color;
// start again outside that width
// remembering the loop will increment this anyway
x += nextObj.Width + pad - 1;
}
}
用法
private static unsafe void Main(string[] args)
{
_objects = Enumerable.Range(0, 25)
.Select((i, i1) => new FillObject(i, _rand.NextColor()))
.ToList();
_largest = _objects.Max(x => x.Width);
var size = _rand.Next(100, 100);
using (var bmp = new Bitmap(size, size, PixelFormat.Format32bppPArgb))
{
var bitmapData = bmp.LockBits(new Rectangle(0, 0, size, size), ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb);
var data = (int*)bitmapData.Scan0;
Generate(new Size(size, size), data, 1);
bmp.UnlockBits(bitmapData);
bmp.Save(@"D:\TestImage.bmp");
}
}
测试100x100 5块1填充
测试100x100 5块2填充
测试100x100 10块2填充
测试100x100 b25会锁定2个填充
测试100x100 25块1个填充
测试100x100 25块0填充
摘要
好吧,前提是
x
到y
的整个平面上移动但是,如果您使用规范(即随机变量),则会发现存在偏差。就是说,在第一行它可以容纳任何喜欢的东西。但是,随后的行将受到限制,因此它将偏向较小的块。然后它会向远处偏移最小的黑色以填充图像。
此外,还有一个对角线效果的偏差,这基本上只是试图将其放入下一行的随机块中的结果。
可能会有更多的微优化来使它更快,但是它非常好并且可以在毫秒内运行
无论如何,我想这是一个很好的起点,您可以添加胡椒粉和盐调味
祝你好运