Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/317.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# 如何验证2d位图是连续的?_C#_Bitmap_Boolean_Area - Fatal编程技术网

C# 如何验证2d位图是连续的?

C# 如何验证2d位图是连续的?,c#,bitmap,boolean,area,C#,Bitmap,Boolean,Area,假设您在C#中有以下结构: 但以下情况并非如此: ...# ...# #... #... 如何确定所有位是否连续 编辑:这是完整的代码,包含了Eric Lippert的答案。从性能上看,这当然可以更严格,但它非常可读 struct Point : IEquatable<Point> { public int X, Y; public Point(int x, int y) { X = x; Y = y; } public bool

假设您在C#中有以下结构:

但以下情况并非如此:

...#
...#
#...
#...
如何确定所有位是否连续

编辑:这是完整的代码,包含了Eric Lippert的答案。从性能上看,这当然可以更严格,但它非常可读

struct Point : IEquatable<Point> {
    public int X, Y;

    public Point(int x, int y) {
        X = x; Y = y;
    }

    public bool Equals(Point obj) {
        return X == obj.X && Y == obj.Y;
    }

    public override bool Equals(object obj) {
        if (obj == null) return false;

        if(obj is Point)
            return Equals((Point)obj);

        return false;
    }

    public override int GetHashCode() {
        return X ^ ~Y;
    }

    public static bool operator == (Point p1, Point p2) {
        return p1.X == p2.X && p1.Y == p2.Y;
    }

    public static bool operator !=(Point p1, Point p2) {
        return p1.X != p2.X || p1.Y != p2.Y;
    }

    public static readonly Point Empty = new Point(int.MinValue, int.MinValue);
}

struct Piece : IEquatable<Piece> {
    public readonly int size;
    public readonly bool[,] data;
    private bool valid;

    public Piece(Piece p) {
        size = p.size;
        valid = p.valid;
        data = (bool[,])p.data.Clone();
    }
    public Piece(int s, bool[,] d) {
        size = s;
        if (d.GetLength(0) != s || d.GetLength(1) != s) throw new ArgumentException();

        data = (bool[,])d.Clone();
        valid = false;

        CalcValidity();
    }

    public bool IsValid {
        get {
            return valid;
        }
    }


    private enum Square {
        White,
        Black,
        Red,
        Blue,
    }

    private int NumSquares(Square[,] map, Square q) {
        int ret = 0;
        for (int y = 0; y < size; y++) {
            for(int x = 0; x < size; x++) {
                if (map[x, y] == q) ret++;
            }
        }
        return ret;
    }

    private Point PickSquare(Square[,] map, Square q) {
        for (int y = 0; y < size; y++) {
            for (int x = 0; x < size; x++) {
                if (map[x, y] == q) return new Point(x, y);
            }
        }
        return Point.Empty;
    }

    private void MakeNeighboursRed(Square[,] map, Point p) {
        if (p.X > 0 && map[p.X - 1, p.Y] == Square.Black) map[p.X - 1, p.Y] = Square.Red;
        if (p.X < size - 1 && map[p.X + 1, p.Y] == Square.Black) map[p.X + 1, p.Y] = Square.Red;

        if (p.Y > 0 && map[p.X, p.Y - 1] == Square.Black) map[p.X, p.Y - 1] = Square.Red;
        if (p.Y < size - 1 && map[p.X, p.Y + 1] == Square.Black) map[p.X, p.Y + 1] = Square.Red;
    }

    private void CalcValidity() {
        Square[,] map = new Square[size, size];

        int count = 0;
        Point square = Point.Empty;


        for (int y = 0; y < size; y++) {
            for (int x = 0; x < size; x++) {
                if (data[x, y]) {
                    map[x, y] = Square.Black;
                    square = new Point(x, y);
                } else {
                    map[x, y] = Square.White;
                }
            }
        }

        if (square != Point.Empty) {
            map[square.X, square.Y] = Square.Red;
        }

        while (true) {
            if (NumSquares(map, Square.Red) == 0) {
                if (NumSquares(map, Square.Black) == 0) {
                    valid = count == size;
                    return;
                } else {
                    valid = false;
                    return;
                }
            } else {
                square = PickSquare(map, Square.Red);

                MakeNeighboursRed(map, square);
                map[square.X, square.Y] = Square.Blue;
                count++;
            }
        } 
    }

    #region IEquatable<Piece> Members

    public bool Equals(Piece other) {
        if (size != other.size) return false;

        for (int y = 0; y < size; y++) {
            for (int x = 0; x < size; x++) {
                if (data[x, y] != other.data[x, y]) return false;
            }
        }
        return true;
    }

    #endregion
}
struct Point:IEquatable{
公共整数X,Y;
公共点(整数x,整数y){
X=X;Y=Y;
}
公共布尔等于(obj点){
返回X==obj.X&&Y==obj.Y;
}
公共覆盖布尔等于(对象对象对象){
if(obj==null)返回false;
如果(obj是点)
返回等于((点)obj);
返回false;
}
公共覆盖int GetHashCode(){
返回X^~Y;
}
公共静态布尔运算符==(点p1,点p2){
返回p1.X==p2.X&&p1.Y==p2.Y;
}
公共静态布尔运算符!=(点p1,点p2){
返回p1.X!=p2.X | | p1.Y!=p2.Y;
}
公共静态只读点空=新点(int.MinValue,int.MinValue);
}
结构件:IEquatable{
公共只读int大小;
公共只读bool[,]数据;
私有布尔有效;
公共件(件p){
尺寸=p.size;
有效=p.valid;
data=(bool[,])p.data.Clone();
}
公共物品(整数s,布尔[,]d){
尺寸=s;
如果(d.GetLength(0)!=s | | d.GetLength(1)!=s)抛出新的ArgumentException();
数据=(bool[,])d.Clone();
有效=错误;
计算有效性();
}
公共布尔是有效的{
得到{
返回有效;
}
}
私有枚举广场{
白色
黑色
红色
蓝色
}
私人整数平方(正方形[,]地图,正方形q){
int-ret=0;
对于(int y=0;y0&&map[p.X-1,p.Y]==Square.Black)map[p.X-1,p.Y]=Square.Red;
如果(p.X0&&map[p.X,p.Y-1]==Square.Black)map[p.X,p.Y-1]=Square.Red;
如果(p.Y
从一个随机的“真”位开始。然后你一次“走”一个北,一个南,一个东,一个西。如果您发现一个“真”位不是“已访问的”,则在一个单独的结构中将该节点标记为“已访问的”,并从那里递归地向各个方向“行走”。如果位为“false”或“visited”,则不执行任何操作并返回到上一个“级别”。如果找不到更多的非“已访问”节点,请计算已访问节点的数量,并与“真实”节点的总数进行比较


编辑:请注意,如果位图很大,递归将耗尽堆栈空间。

以下是一种考虑不使用递归的泛洪填充算法的方法

首先,将每个正方形设置为白色(空白)或黑色(填充)。问题是“黑色区域是否相邻?”

您可以使用以下算法:

  • 如果没有黑色方块,那么确实没有不连续的黑色区域,那么就完成了
  • 否则,至少有一个黑色正方形。选择任何一个黑色正方形并将其变为红色
  • 如果没有红色方块和黑色方块,那么就完成了,黑色区域是连续的
  • 如果没有红色方块,只有一个或多个黑色方块,那么就完成了。黑色区域不连续。仍然是黑色的区域与蓝色区域不连续
  • 否则,必须至少有一个红方块。随便选一个红场。把它所有的黑色邻居都变成红色,然后变成蓝色
  • 返回到步骤3
  • 看到了吗?红色方块是未填充洪水的区域的“边缘”。蓝色的方块是被淹没的区域。如果蓝色淹没了所有的黑色,那么它一定是连续的

    更新:关于你的评论:


    非常感谢你!这太完美了。我喜欢你的博客,尤其是a
    ...#
    ...#
    #...
    #...
    
    struct Point : IEquatable<Point> {
        public int X, Y;
    
        public Point(int x, int y) {
            X = x; Y = y;
        }
    
        public bool Equals(Point obj) {
            return X == obj.X && Y == obj.Y;
        }
    
        public override bool Equals(object obj) {
            if (obj == null) return false;
    
            if(obj is Point)
                return Equals((Point)obj);
    
            return false;
        }
    
        public override int GetHashCode() {
            return X ^ ~Y;
        }
    
        public static bool operator == (Point p1, Point p2) {
            return p1.X == p2.X && p1.Y == p2.Y;
        }
    
        public static bool operator !=(Point p1, Point p2) {
            return p1.X != p2.X || p1.Y != p2.Y;
        }
    
        public static readonly Point Empty = new Point(int.MinValue, int.MinValue);
    }
    
    struct Piece : IEquatable<Piece> {
        public readonly int size;
        public readonly bool[,] data;
        private bool valid;
    
        public Piece(Piece p) {
            size = p.size;
            valid = p.valid;
            data = (bool[,])p.data.Clone();
        }
        public Piece(int s, bool[,] d) {
            size = s;
            if (d.GetLength(0) != s || d.GetLength(1) != s) throw new ArgumentException();
    
            data = (bool[,])d.Clone();
            valid = false;
    
            CalcValidity();
        }
    
        public bool IsValid {
            get {
                return valid;
            }
        }
    
    
        private enum Square {
            White,
            Black,
            Red,
            Blue,
        }
    
        private int NumSquares(Square[,] map, Square q) {
            int ret = 0;
            for (int y = 0; y < size; y++) {
                for(int x = 0; x < size; x++) {
                    if (map[x, y] == q) ret++;
                }
            }
            return ret;
        }
    
        private Point PickSquare(Square[,] map, Square q) {
            for (int y = 0; y < size; y++) {
                for (int x = 0; x < size; x++) {
                    if (map[x, y] == q) return new Point(x, y);
                }
            }
            return Point.Empty;
        }
    
        private void MakeNeighboursRed(Square[,] map, Point p) {
            if (p.X > 0 && map[p.X - 1, p.Y] == Square.Black) map[p.X - 1, p.Y] = Square.Red;
            if (p.X < size - 1 && map[p.X + 1, p.Y] == Square.Black) map[p.X + 1, p.Y] = Square.Red;
    
            if (p.Y > 0 && map[p.X, p.Y - 1] == Square.Black) map[p.X, p.Y - 1] = Square.Red;
            if (p.Y < size - 1 && map[p.X, p.Y + 1] == Square.Black) map[p.X, p.Y + 1] = Square.Red;
        }
    
        private void CalcValidity() {
            Square[,] map = new Square[size, size];
    
            int count = 0;
            Point square = Point.Empty;
    
    
            for (int y = 0; y < size; y++) {
                for (int x = 0; x < size; x++) {
                    if (data[x, y]) {
                        map[x, y] = Square.Black;
                        square = new Point(x, y);
                    } else {
                        map[x, y] = Square.White;
                    }
                }
            }
    
            if (square != Point.Empty) {
                map[square.X, square.Y] = Square.Red;
            }
    
            while (true) {
                if (NumSquares(map, Square.Red) == 0) {
                    if (NumSquares(map, Square.Black) == 0) {
                        valid = count == size;
                        return;
                    } else {
                        valid = false;
                        return;
                    }
                } else {
                    square = PickSquare(map, Square.Red);
    
                    MakeNeighboursRed(map, square);
                    map[square.X, square.Y] = Square.Blue;
                    count++;
                }
            } 
        }
    
        #region IEquatable<Piece> Members
    
        public bool Equals(Piece other) {
            if (size != other.size) return false;
    
            for (int y = 0; y < size; y++) {
                for (int x = 0; x < size; x++) {
                    if (data[x, y] != other.data[x, y]) return false;
                }
            }
            return true;
        }
    
        #endregion
    }
    
    public static IEnumerable<Tile> GetNeighbours(Tile tile)
    {
         ... yield return the north, south, east and west neighbours
         ... if they exist and they are on
    }
    
    bool HasExactlyOneRegion()
    {
        return (tilesTurnedOn.Count == 0) ? 
            false : 
            TransitiveAndReflexiveClosure(GetNeighbours, tilesTurnedOn.First()).Count == tilesTurnedOn.Count;
    }