Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.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#_Unity3d - Fatal编程技术网

C# 查找一系列连接点之间的闭合环

C# 查找一系列连接点之间的闭合环,c#,unity3d,C#,Unity3d,所以我一直在尝试如何解决我最初只是一个简单的问题——结果我是个白痴,根本不知道我在做什么 首先,我的数据结构如下: public class Points{ public List<Points> connectsTo = new List<Points>(); public Vector3 position; } // main script List<Points> allWorldPoints = new List<Points&

所以我一直在尝试如何解决我最初只是一个简单的问题——结果我是个白痴,根本不知道我在做什么

首先,我的数据结构如下:

public class Points{
    public List<Points> connectsTo = new List<Points>();
    public Vector3 position;
}
// main script 
List<Points> allWorldPoints = new List<Points>();
公共类积分{
public List connectsTo=新列表();
公共向量3位置;
}
//主脚本
List allWorldPoints=新列表();
我的想法是,这些点是创建墙的连接件,我需要从中找到房间。以下是我试图实现的目标:

房间不一定是方形/矩形,它们可以是L形或T形等

问题是我不知道如何解决这个问题的逻辑,所以我在寻求建议,因为这个逻辑真的让我困惑

  • 从任何一点开始
  • 遍历连接点,直到回到起点。从找到的所有可能路径中选择点数最少的路径;你刚刚找到一个房间
  • 把新找到的房间存放起来
  • 选择一个不属于任何已找到房间的新起点,然后重复2
  • 当没有未指定给房间的点或未找到更多闭合路径时结束
  • 顺便说一下,您的类应该命名为
    Point
    而不是
    Points

    更新:我添加了一个工作示例

    好的,首先让我们获得必要的基础设施。我将实现两个类:
    Point
    Room
    ImmutableStack
    (后者用于简化遍历路径):

    我们得到了预期的两个房间


    请注意,例如,如果将
    immutualStack
    更改为
    ImmutableHashSet
    ,则可以提高算法的性能。

    仅列出点是不够的,您至少需要为每个连接和构建墙列出元组。我不明白,用洪水填房间可以吗?该视图显示了使用一个点(该点还包含其连接到的点的列表)进行连接的点。。还有为什么我需要我看不到那里的关系?编辑:unity似乎也不支持元组。我认为您使用的术语在代码中有点混乱。
    有一个
    点列表
    。然后,您还创建了一个
    点列表
    。是的,在我的主脚本中,这是一个点列表,每个点都有自己连接的点列表。什么是更好的结构?啊,那么一个点列表只适用于一个多边形?这有点小问题,如果你在房间1中看到,有一个点在左侧看起来基本上是多余的,这与点计数有点偏差。虽然这一点还有其他用途——因此点数可能不准确=/@Dave Flood fill,但我不知道这意味着什么@Martheen@Dave我看不出问题所在。该点将与其相邻点相连,因此将成为Room1路径的一部分。一旦它成为Room1的一部分,它的迪卡德就成为下一次搜索的出发点。@Dave谷歌它?这只是一个确定面积的算法。在你的例子中,你会得到3个区域,其中两个是房间。
    public class ImmutableStack<T> : IEnumerable<T>
    {
        private readonly T head;
        private readonly ImmutableStack<T> tail;
        public int Count { get; }
        public static readonly ImmutableStack<T> Empty = new ImmutableStack<T>();
    
        private ImmutableStack()
        {
            head = default(T);
            tail = null;
            Count = 0;
        }
    
        private ImmutableStack(T head, ImmutableStack<T> tail)
        {
            Debug.Assert(tail != null);
            this.head = head;
            this.tail = tail;
            Count = tail.Count + 1;
        }
    
        public ImmutableStack<T> Push(T item) => new ImmutableStack<T>(item, this);
        public T Peek()
        {
            if (this == Empty)
                throw new InvalidOperationException("Can not peek an empty stack.");
    
            return head;
        }
    
        public ImmutableStack<T> Pop()
        {
            if (this == Empty)
                throw new InvalidOperationException("Can not pop an empty stack.");
    
            return tail;
        }
    
        public IEnumerator<T> GetEnumerator()
        {
            var current = this;
    
            while (current != Empty)
            {
                yield return current.Peek();
                current = current.tail;
            }
        }
    
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
        public override string ToString() => string.Join(" -> ", this);
    }
    
    public class Point: IEquatable<Point>
    {
        private readonly List<Point> connectedPoints;
        public int X { get; }
        public int Y { get; }
        public IEnumerable<Point> ConnectedPoints => connectedPoints.Select(p => p);
    
        public Point(int x, int y)
        {
            X = x;
            Y = y;
            connectedPoints = new List<Point>();
        }
    
        public void ConnectWith(Point p)
        {
            Debug.Assert(p != null);
            Debug.Assert(!Equals(p));
    
            if (!connectedPoints.Contains(p))
            {
                connectedPoints.Add(p);
                p.connectedPoints.Add(this);
            }
        }
    
        public bool Equals(Point p)
        {
            if (ReferenceEquals(p, null))
                return false;
    
            return X == p.X && Y == p.Y;
        }
    
        public override bool Equals(object obj) => this.Equals(obj as Point);
        public override int GetHashCode() => X ^ Y;
        public override string ToString() => $"[{X}, {Y}]";
    }
    
    public class Room
    {
        public IEnumerable<Point> Points { get; }
        public Room(IEnumerable<Point> points)
        {
            Points = points;
        }
    }
    
    public static IEnumerable<Room> GetRooms(this IEnumerable<Point> points)
    {
        if (points.Count() < 3) //need at least 3 points to build a room
            yield break;
    
        var startCandidates = points;
    
        while (startCandidates.Any())
        {
            var start = startCandidates.First();
            var potentialRooms = GetPaths(start, start, ImmutableStack<Point>.Empty).OrderBy(p => p.Count);
    
            if (potentialRooms.Any())
            {
                var roomPath = potentialRooms.First();
                yield return new Room(roomPath);
                startCandidates = startCandidates.Except(roomPath);
            }
            else
            {
                startCandidates = startCandidates.Except(new[] { start });
            }
        }
    }
    
    private static IEnumerable<ImmutableStack<Point>> GetPaths(Point start, Point current, ImmutableStack<Point> path)
    {
        if (current == start &&
            path.Count > 2) //discard backtracking
        {
            yield return path;
        }
        else if (path.Contains(current))
        {
            yield break;
        }
        else
        {
            var newPath = path.Push(current);
    
            foreach (var point in current.ConnectedPoints)
            {
                foreach (var p in GetPaths(start, point, newPath))
                {
                    yield return p;
                }
            }
        }
    }
    
        public static void Main(string[] args)
        {
            var p1 = new Point(0, 0);
            var p2 = new Point(0, 1);
            var p3 = new Point(0, 2);
            var p4 = new Point(1, 2);
            var p5 = new Point(1, 1);
            var p6 = new Point(1, 0);
            var p7 = new Point(2, 0);
            var p8 = new Point(2, 1);
            p1.ConnectWith(p2);
            p2.ConnectWith(p3);
            p3.ConnectWith(p4);
            p4.ConnectWith(p5);
            p5.ConnectWith(p6);
            p6.ConnectWith(p1);
            p6.ConnectWith(p7);
            p7.ConnectWith(p8);
            p8.ConnectWith(p5);
            var rooms = new[] { p1, p2, p3, p4, p5, p6, p7, p8 }.GetRooms();
        }