public ExplicitOutlineShape(OutlineShape template, InsideShapeDelegate isReserved) : this(template.XSize, template.YSize) { for (int x = 0; x < this.XSize; x++) { for (int y = 0; y < this.YSize; y++) { this.SetValue(x, y, (template[x, y] && (isReserved == null || !isReserved(x, y)))); } } }
/// <summary> /// Returns the largest subset of the template shape whose squares are all connected to each other. /// </summary> /// <param name="template"></param> /// <param name="isReserved">defines the maze's reserved areas</param> /// <returns></returns> public static OutlineShape ConnectedSubset(OutlineShape template, InsideShapeDelegate isReserved) { ExplicitOutlineShape result = new ExplicitOutlineShape(template, isReserved); #region Scan the shape for connected areas. byte subsetId = 1; int largestAreaSize = 0; byte largestAreaId = 0; for (int x = 0; x < result.XSize; x++) { for (int y = 0; y < result.YSize; y++) { if (result.squares[x, y] == 1 && subsetId < byte.MaxValue) { int areaSize = result.FillSubset(x, y, ++subsetId); if (areaSize > largestAreaSize) { largestAreaSize = areaSize; largestAreaId = subsetId; } } } } #endregion #region Leave only the largest subset, eliminate all others. for (int x = 0; x < result.XSize; x++) { for (int y = 0; y < result.YSize; y++) { result.SetValue(x, y, (result.squares[x, y] == largestAreaId)); } } #endregion return(result); }
public OutlineShape RotatedOrFlipped(RotateFlipType rft) { // Note: flipX and flipY will be evaluated after swapping X and Y. bool swapXY = false, flipX = false, flipY = false; // Note: There are eight different rotate/flip operations but 16 names in the RotateFlipType. // Every operation has two names which give the same enum value. switch (rft) { default: case RotateFlipType.RotateNoneFlipNone: //case RotateFlipType.Rotate180FlipXY: break; case RotateFlipType.RotateNoneFlipX: //case RotateFlipType.Rotate180FlipY: flipX = true; break; case RotateFlipType.RotateNoneFlipY: //case RotateFlipType.Rotate180FlipX: flipX = true; break; case RotateFlipType.Rotate90FlipNone: //case RotateFlipType.Rotate270FlipXY: swapXY = flipX = true; break; case RotateFlipType.Rotate270FlipNone: //case RotateFlipType.Rotate90FlipXY: swapXY = flipY = true; break; case RotateFlipType.RotateNoneFlipXY: //case RotateFlipType.Rotate180FlipNone: flipX = flipY = true; break; case RotateFlipType.Rotate90FlipX: //case RotateFlipType.Rotate270FlipY: swapXY = true; break; case RotateFlipType.Rotate90FlipY: //case RotateFlipType.Rotate270FlipX: swapXY = flipX = flipY = true; break; } int resultXSize, resultYSize; if (swapXY) { resultXSize = this.ySize; resultYSize = this.xSize; } else { resultXSize = this.xSize; resultYSize = this.ySize; } InsideShapeDelegate test = delegate(int x, int y) { int xx, yy; if (swapXY) { xx = y; yy = x; } else { xx = x; yy = y; } if (flipX) { xx = this.xSize - 1 - xx; } if (flipY) { yy = this.ySize - 1 - yy; } return(this[xx, yy]); }; // Note: We return an ExplicitOutlineShape because that is more efficiently evaluated. // The TilesOutelineShape also requires an ExplicitOutlineShape for its tile pattern. return(new ExplicitOutlineShape(new DelegateOutlineShape(resultXSize, resultYSize, test))); }
public OutlineShape Inverse() { InsideShapeDelegate test = delegate(int x, int y) { return(!this[x, y]); }; return(new DelegateOutlineShape(this.XSize, this.YSize, test)); }
/// <summary> /// Returns this shape, augmented by all totally enclosed areas. /// Reserved areas define additional borders around enclosed areas. /// </summary> /// <param name="isReserved">defines the maze's reserved areas</param> /// <returns></returns> public OutlineShape Closure(InsideShapeDelegate isReserved) { return(ExplicitOutlineShape.Closure(this, isReserved)); }
/// <summary> /// Returns the largest subset of this shape whose squares are all connected to each other. /// </summary> /// <returns></returns> public OutlineShape ConnectedSubset(InsideShapeDelegate isReserved) { return(ExplicitOutlineShape.ConnectedSubset(this, isReserved)); }
public DelegateOutlineShape(int xSize, int ySize, InsideShapeDelegate test) : base(xSize, ySize) { this.test = test; }
/// <summary> /// Returns the template shape, augmented by all totally enclosed areas. /// </summary> /// <param name="template"></param> /// <param name="isReserved">defines the maze's reserved areas</param> /// <returns></returns> public static OutlineShape Closure(OutlineShape template, InsideShapeDelegate isReserved) { ExplicitOutlineShape result = new ExplicitOutlineShape(template.Inverse()); #region Scan and mark the reserved areas. if (isReserved != null) { byte reservedId = 3; for (int x = 0; x < result.XSize; x++) { for (int y = 0; y < result.YSize; y++) { if (isReserved(x, y)) { result.squares[x, y] = reservedId; } } } } #endregion #region Scan all outside areas. byte outsideId = 2; int x0 = 0, x1 = result.XSize - 1, y0 = 0, y1 = result.YSize - 1; for (int x = 0; x < result.XSize; x++) { if (result.squares[x, y0] == 1) { result.FillSubset(x, y0, outsideId); } if (result.squares[x, y1] == 1) { result.FillSubset(x, y1, outsideId); } } for (int y = 0; y < result.YSize; y++) { if (result.squares[x0, y] == 1) { result.FillSubset(x0, y, outsideId); } if (result.squares[x1, y] == 1) { result.FillSubset(x1, y, outsideId); } } #endregion #region Add the areas which were not reached. for (int x = 0; x < result.XSize; x++) { for (int y = 0; y < result.YSize; y++) { // 0: square is part of the template (not part of its inverse) // 1: square is not part of the template, but was not reached result.SetValue(x, y, (result.squares[x, y] <= 1)); } } #endregion return(result); }