private void SolvePuzzle(int puzzle) { var initboard = new Board868(puzzle, new Board868(puzzle), 0); var res = initboard.Solve(puzzle * puzzle); WriteLine(res.Count); foreach (var board in res) { WriteLine(@"{0} {1} {2}", board.Row, board.Col, board.SquareSize); } }
/// <summary> /// Constructor for a child board in the search process /// </summary> /// <remarks> /// When created, this board will have the next cell in the board that needs filling in /// _placeRow, _placeCol. We scan from the top down so everything above _placeRow is /// guaranteed to be filled in the resulting board. /// </remarks> /// <param name="boardSize">Size of the board</param> /// <param name="parent">Parent in the search process</param> /// <param name="searchRow">Where we should begin the search</param> public Board868(int boardSize, Board868 parent, int searchRow) { // Inherit stuff from the parent BoardSize = boardSize; _board = (int[, ])parent._board.Clone(); _ulSize = parent._ulSize; _urSize = parent._urSize; // Search out the next cell that needs filling for (var iRow = searchRow; iRow < BoardSize; iRow++) { for (var iCol = 0; iCol < BoardSize; iCol++) { // Searching for an empty space if (_board[iRow, iCol] == 0) { // If we find one then we'll start there _placeCol = iCol; _placeRow = iRow; return; } } } }
/// <summary> /// Solve the board using maxAllowed or fewer squares /// </summary> /// <remarks> /// This board will already be filled in completely above _curRow /// </remarks> /// <param name="maxAllowed"></param> /// <returns></returns> public List <Board868> Solve(int maxAllowed) { // List of child boards leading to a solution - no such solution yet List <Board868> curBest = null; // Are there no more squares available? if (maxAllowed == 0) { // Not solvable return(null); } // Have we filled up the board? if (_placeRow < 0) { // return the solution // ...which happens to be empty for this board - i.e., there are no // steps to solve this board - it's already solved - so return // the empty list. return(new List <Board868>()); } // Still searching for a solution // Find biggest size we can fit below and to the right at the current placement location var biggestSize = FindBiggestFit(_placeRow, _placeCol); // ...and fill it up FillSquare(_placeRow, _placeCol, biggestSize); // For all squares which will fit here for (var iSize = biggestSize; iSize > 0; iSize--) { // Is this an acceptable size for symmetry breaking? if (!BreaksSymmetry(iSize)) { // Spawn a child board with the square set in place var newBoard = new Board868(BoardSize, this, _placeRow); // Recursively solve the new board with the minimal squares var trialSolution = newBoard.Solve(maxAllowed - 1); // Did we find a solution? if (trialSolution != null) { // This is our best current solution curBest = trialSolution; // Ensure that future solutions do better than this maxAllowed = trialSolution.Count + 1; // Record the currently best size to place at this location _bestSquareSize = iSize; } } // Try the next smaller sized square // We do this by clearing the lower right border ClearLowerRightBorder(_placeRow, _placeCol, iSize); } // Did we find a solution among our children? // Add our board to it curBest?.Add(this); // Return best solution found return(curBest); }