C# - 递归函数问题

时间:2010-09-18 21:39:43

标签: c# recursion

这是我的功能:

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个甚至更奇怪的东西),这似乎也会遇到同样的问题。

3 个答案:

答案 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。

aleftaright中,您需要在单独的Map s中获得所需的钻石的左半部分和右半部分,您需要以某种方式将它们连接在一起(不应该是像你这样聪明的家伙太难了:)。 leftright显示Map的文字表示(请注意中心的重叠):

left

             #              
            #.
           #..
          #...
         #....
        #.....
       #......
      #.......
     #........
    #.........
   #..........
  #...........
 #............
#.............
 #............
  #...........
   #..........
    #.........
     #........
      #.......
       #......
        #.....
         #....
          #...
           #..
            #.
             #              

right

             #                      
             .#            
             ..#           
             ...#          
             ....#         
             .....#        
             ......#       
             .......#      
             ........#     
             .........#    
             ..........#   
             ...........#  
             ............# 
             .............#
             ............# 
             ...........#  
             ..........#   
             .........#    
             ........#     
             .......#      
             ......#       
             .....#        
             ....#         
             ...#          
             ..#           
             .#            
             #   

您需要清理它并将所有类更改回您自己的类。我希望这有帮助!

答案 2 :(得分:0)

你不想要像

这样的东西
 if(grid[x,y] != 0) // or whatever the initial value is

而不是

 if(grid[x,y] != value)

否则,当你长大后,它会重新回到种子点。