这是我的功能:
static Map AddFormation(Map _map, Tile tile, int x, int y, int length,
Random rand, Tile endTile = (Tile)Int32.MaxValue)
{
//so a call to AddFormation without the endTile will work, if I don't want a border.
if ((int)endTile == Int32.MaxValue) endTile = tile;
if (x >= 0 && x < _map.Data.GetLength(0) && y >= 0 && y < _map.Data.GetLength(1))
{
if (_map.Data[x, y].Tile != tile)
{
if (length > 0)
{
_map.Data[x, y].Tile = tile;
int newlength = length - 1;
AddFormation(_map, tile, x, y - 1, newlength, rand, endTile); // ^
AddFormation(_map, tile, x, y + 1, newlength, rand, endTile); // v
AddFormation(_map, tile, x - 1, y, newlength, rand, endTile); // <-
AddFormation(_map, tile, x + 1, y, newlength, rand, endTile); // ->
}
else
{
_map.Data[x, y].Tile = endTile;
}
}
}
return _map;
}
我有一个瓷砖枚举,这是为了让我的生活更容易使用瓷砖。 我有一个Cell类,其中包含一个名为“Tile”的Tile枚举和其他信息(对此不重要) Map类包含一个名为Data的Cell [,]组。
我想要实现的是在特定点创建特定区块的块,我稍后会将随机化纳入此(因此它不仅仅是钻石)但是我把它拿出来看看是否是我的问题的原因。
问题是对这个函数的调用总是产生比它们更宽的块,我不能为我的生活看到原因..
我创建了一个测试函数,看看如果我使用类似的东西会发生什么:
public static int[,] Add(int[,] grid, int x, int y, int length, int value)
{
if (x >= 0 && y >= 0 && x < grid.GetLength(0) && y < grid.GetLength(1))
{
if(grid[x,y] != value)
{
if(length > 0)
{
grid[x, y] = value;
Add(grid, x - 1, y, length - 1, value);
Add(grid, x + 1, y, length - 1, value);
Add(grid, x, y - 1, length - 1, value);
Add(grid, x, y + 1, length - 1, value);
}
}
}
return grid;
}
如果你足够大(5个产生完美的钻石,6个产生奇怪的形状,11个甚至更奇怪的东西),这似乎也会遇到同样的问题。
答案 0 :(得分:1)
当你说:
if(grid[x,y] != value)
如果您没有遇到任何已经设置为此值的块,那么您告诉它只能继续沿着这条“腿”行进。问题是,一旦你得到一个足够长的长度,出现点顶部的“腿”向左和向右“旋转”,所以当递归最终回到它开始尝试的点时向左或向右走,那里已经有一个正方形,你马上回来。
看起来您想要取if(length > 0)
并将放在<{em> if(grid[x,y] != value)
块之后,而不是放在其中。这样,您只需“设置”该值(如果尚未设置),但您将继续直到达到适当的长度。
当然,由于“分支”(即if
语句)花费的时间比“赋值”(即在数组中设置一个值)要长,所以你也可以完全删除if(grid[x,y] != value)
,并且风险将点数设置为相同的值多次,因为它比比较当前值便宜。
if (x >= 0 && y >= 0 && x < grid.GetLength(0) && y < grid.GetLength(1))
{
grid[x, y] = value;
if(length > 0)
{
Add(grid, x - 1, y, length - 1, value);
Add(grid, x + 1, y, length - 1, value);
Add(grid, x, y - 1, length - 1, value);
Add(grid, x, y + 1, length - 1, value);
}
}
return grid;
答案 1 :(得分:1)
好的,花了很长时间在这上面(我喜欢递归),这是解决方案的中途(可能很难解释):
问题在于您允许“路径”沿着已经分配为endTile
的单元格回溯。如果你看一下你的第一种方法,你可以在搜索点搜索后直接搜索。你只需删除它。
这是我正在使用的代码(注意它调用AddFormationAlt
两次,一次上升,一次下降):
class Program
{
static string left;
static string right;
static void Main(string[] args)
{
int size = 20;
int sizem = size*2 + 1;
Map m = new Map(new int[sizem,sizem]);
AddFormationAlt(m, 1, size, size, size-1, 2);
var l = left;
var r = right;
}
private class Map
{
public int[,] Data { get; set; }
public Map(int[,] data)
{
Data = data;
}
public string Print()
{
StringBuilder sb = new StringBuilder();
for (int x = 0; x < Data.GetLength(0); x++)
{
for (int y = 0; y < Data.GetLength(1); y++)
sb.Append(Data[y, x] == 0 ? " " : Data[y,x] == 1 ? "." : "#");
sb.AppendLine();
}
return sb.ToString();
}
}
static void AddFormationAlt(Map _map, int tile, int x, int y, int length, int endTile)
{
// You may need to change the cloning method when you change the tiles from ints
Map m1 = new Map((int[,])_map.Data.Clone());
Map m2 = new Map((int[,])_map.Data.Clone());
// Contains the left and right half of the Map you want, you need to join these together.
Map aleft = AddFormationAlt(m1, true, tile, x, y, length, endTile);
Map aright = AddFormationAlt(m2, false, tile, x, y + 1, length, endTile);
left = aleft.Print();
right = aright.Print();
}
static Map AddFormationAlt(Map _map, bool up, int tile, int x, int y, int length, int endTile)
{
if (x >= 0 && x < _map.Data.GetLength(0) && y >= 0 && y < _map.Data.GetLength(1))
{
if (_map.Data[y, x] != tile)
{
if (length > 0)
{
_map.Data[y, x] = tile;
int newlength = length - 1;
// Either go 'up' or 'down'
if(up)
AddFormationAlt(_map, true, tile, x, y - 1, newlength, endTile); // ^
else
AddFormationAlt(_map, false, tile, x, y + 1, newlength, endTile); // v
AddFormationAlt(_map, up, tile, x - 1, y, newlength, endTile); // <-
AddFormationAlt(_map, up, tile, x + 1, y, newlength, endTile); // ->
}
else
_map.Data[y, x] = endTile;
}
}
return _map;
}
}
我已将您的所有Data[x, y]
更改为Data[y, x]
,因为这是我通常存储它们的方式,然后它可以使用xD。
在aleft
和aright
中,您需要在单独的Map
s中获得所需的钻石的左半部分和右半部分,您需要以某种方式将它们连接在一起(不应该是像你这样聪明的家伙太难了:)。 left
和right
显示Map
的文字表示(请注意中心的重叠):
left
:
#
#.
#..
#...
#....
#.....
#......
#.......
#........
#.........
#..........
#...........
#............
#.............
#............
#...........
#..........
#.........
#........
#.......
#......
#.....
#....
#...
#..
#.
#
right
:
#
.#
..#
...#
....#
.....#
......#
.......#
........#
.........#
..........#
...........#
............#
.............#
............#
...........#
..........#
.........#
........#
.......#
......#
.....#
....#
...#
..#
.#
#
您需要清理它并将所有类更改回您自己的类。我希望这有帮助!
答案 2 :(得分:0)
你不想要像
这样的东西 if(grid[x,y] != 0) // or whatever the initial value is
而不是
if(grid[x,y] != value)
否则,当你长大后,它会重新回到种子点。