internal static void FillMatrix(int[,] matrix, MatrixCell startupCell) { var currentCell = startupCell; var dirIndex = 0; while (IsCellPassable(matrix, currentCell)) { matrix[currentCell.X, currentCell.Y] = currentCell.Value; while (!IsNextCellPassable(matrix, currentCell, dirIndex) && CanCellMoveSomewhere(matrix, currentCell, dirIndex)) { dirIndex = (dirIndex + 1) % DirX.Length; } currentCell.X += DirX[dirIndex]; currentCell.Y += DirY[dirIndex]; currentCell.Value++; } var nextStartupCell = FindFirstAvailableCell(matrix); if (nextStartupCell == null) { return; } nextStartupCell.Value = currentCell.Value; FillMatrix(matrix, nextStartupCell); }
List<MatrixCell> _Items; // list of MatrixCell public MatrixCells(ReportDefn r, ReportLink p, XmlNode xNode) : base(r, p) { MatrixCell m; _Items = new List<MatrixCell>(); // Loop thru all the child nodes foreach(XmlNode xNodeLoop in xNode.ChildNodes) { if (xNodeLoop.NodeType != XmlNodeType.Element) continue; switch (xNodeLoop.Name) { case "MatrixCell": m = new MatrixCell(r, this, xNodeLoop); break; default: m=null; // don't know what this is // don't know this element - log it OwnerReport.rl.LogError(4, "Unknown MatrixCells element '" + xNodeLoop.Name + "' ignored."); break; } if (m != null) _Items.Add(m); } if (_Items.Count == 0) OwnerReport.rl.LogError(8, "For MatrixCells at least one MatrixCell is required."); else _Items.TrimExcess(); }
private static bool IsCellPassable(int[,] matrix, MatrixCell currentCell) { var isCellPassable = currentCell.X >= 0 && currentCell.X < matrix.GetLongLength(0) && currentCell.Y >= 0 && currentCell.Y < matrix.GetLongLength(1) && matrix[currentCell.X, currentCell.Y] == 0; return isCellPassable; }
private static bool IsNextCellPassable(int[,] matrix, MatrixCell currentCell, int dirIndex) { var nextCell = new MatrixCell { X = currentCell.X + DirX[dirIndex], Y = currentCell.Y + DirY[dirIndex] }; return IsCellPassable(matrix, nextCell); }
private static bool CanCellMoveSomewhere(int[,] matrix, MatrixCell currentCell, int dirIndex) { for (var i = 0; i < DirX.Length; i++) { dirIndex = (dirIndex + 1) % DirX.Length; if (IsNextCellPassable(matrix, currentCell, dirIndex)) { return true; } } return false; }
internal static MatrixCell FindFirstAvailableCell(int[,] matrix) { for (var row = 0; row < matrix.GetLength(0); row++) { for (var col = 0; col < matrix.GetLength(0); col++) { if (matrix[row, col] == 0) { var firstEmptyCell = new MatrixCell(row, col); return firstEmptyCell; } } } return null; }
/// <summary> /// Sets the bits in the region starting at location and having /// given width and height /// </summary> /// <param name="location">Top Left of the the Region</param> /// <param name="width">Width of the Region</param> /// <param name="height">Height of the Region</param> internal void SetRegion(MatrixCell location, int width, int height) { if (BitOrientation == Orientation.Horizontal) { // Optimization: If the region is only 1 bit wide and high if ((width == 1) && (height == 1)) { this[location.Row, location.Col] = true; return; } for (var row = 0; row < height; row++) { for (var col = 0; col < width; col++) { this[location.Row + row, location.Col + col] = true; } } } // Interchange Row & Column and width & height if the BitOrientation is Vertical else { // Optimization: If the region is only 1 bit wide and high if ((width == 1) && (height == 1)) { this[location.Col, location.Row] = true; return; } for (var row = 0; row < width; row++) { for (var col = 0; col < height; col++) { this[location.Col + row, location.Row + col] = true; } } } }
/// <summary> /// Finds the next empty region of given width and height starting /// from the startIndex row /// </summary> /// <param name="startIndex">The row to start the search from</param> /// <param name="width">Width of the Region</param> /// <param name="height">Height of the Region</param> /// <returns></returns> internal MatrixCell FindRegion(long startIndex, int width, int height) { // Swap width and height if the BitOrientation is Vertical if ((BitOrientation == Orientation.Vertical) && (width != height)) { var temp = width; width = height; height = temp; } var invalidCell = new MatrixCell(-1, -1); if (startIndex < 0 || startIndex >= _rowsInternal) throw new ArgumentOutOfRangeException(nameof(startIndex)); if (startIndex + (height - 1) >= _rowsInternal) throw new ArgumentOutOfRangeException(nameof(width), $"Cannot fit item having height of {height} rows in {_rowsInternal - startIndex} rows!"); if ((width < 1) || (width > 60)) throw new ArgumentOutOfRangeException(nameof(width), $"Length of the item must be in the range 1 - {MaxBitsPerItem}!"); if (width > _columnsInternal) throw new ArgumentOutOfRangeException(nameof(width), $"Length cannot be greater than number of columns in the BitMatrix!"); // Optimization: If both width and height are 1 then use a faster // loop to find the next empty bit if ((width == 1) && (height == 1)) { for (var row = startIndex; row < _rowsInternal; row++) { for (var col = 0; col < _columnsInternal; col++) { if (!this[row, col]) { // Swap the row and col values if the BitOrientation is Vertical return (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, col) : new MatrixCell(col, row); } } } // If the code has reached here it means that it did not find any unset // bit in the entire _data. Simply return from here. return invalidCell; } var mask = (((UInt64)1) << width) - 1; for (var row = startIndex; row < _rowsInternal; row++) { // Quickcheck: If the row is empty then no need to check individual bits in the row if (!RowHasData(row)) { // Current column has no bits set. Check the bits in the next (height - 1) // rows starting at the same column position (0) to check if they are unset if (!AnyBitsSetInRegion(row, 0, width, height)) { // Swap the row and col values if the BitOrientation is Vertical return (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, 0) : new MatrixCell(0, row); } } // Row is not empty and has some set bits. Check if there are // 'width' continuous unset bits in the column. // 1. Check the first 'width' bits var rowData = (UInt64)0; var col = 0; for (; col < width; col++) { rowData <<= 1; rowData |= this[row, col] ? (UInt64)1 : (UInt64)0; } if ((rowData & mask) == 0) { // Current column has 'width' unset bits starting from 0 position. // Check the bits in the next (height - 1) rows starting at the same // column position (0) to check if they are unset if (!AnyBitsSetInRegion(row, 0, width, height)) { // Swap the row and col values if the BitOrientation is Vertical return (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, 0) : new MatrixCell(0, row); } } // Shift the rowData by 1 bit and clear the (width + 1)th most significant bit. // This way a set of 'width' continuous bits is matched against the mask // to check if all the bits are zero. var colBegin = 0; while (col < _columnsInternal) { rowData <<= 1; rowData &= mask; rowData |= this[row, col++] ? (UInt64)1 : (UInt64)0; colBegin++; if ((rowData & mask) != 0) continue; // Current column has 'width' unset bits starting from colBegin position. // Check the bits in the next (height - 1) rows starting at the same // column position (colBegin) to check if they are unset if (AnyBitsSetInRegion(row, colBegin, width, height)) continue; // Swap the row and col values if the BitOrientation is Vertical return (BitOrientation == Orientation.Horizontal) ? new MatrixCell(row, colBegin) : new MatrixCell(colBegin, row); } } return invalidCell; }