private static int solveBoard(int rows, int cols, int[] board) {
    int length = rows * cols;

    // Create the transformation matrix.
    int[][] transform = makeTransformMatrix(rows, cols);
    
    // Perform Gauss-Jordan elimination on transformation matrix.
    gaussJordan(transform, board);
    
    int rank = getRank(transform);
    
    /* Check if our system of equations is solvable.
     * Everything below rank in the row reduced matrix should be 0, so if board is non-zero,
     * that means one of our transformed equations is 0 = 1, which is impossible.
     */
    for (int i = rank; i < length; i++) {
      if (board[i] != 0) {
        return -1;
      }
    }
    
    /* Our board is solvable, so check all solutions and find the least moves needed.
     * Given x free positions, we will have 2^x possible solutions.
     */
    List<Integer> positions = getFreePositions(transform);
    int solutions = (int) Math.pow(2, positions.size());
    int minMoves = Integer.MAX_VALUE;
    for (int x = 0; x < solutions; x++) {
      // Fill a solution with our free variables and solve for the remainder.
      int[] solution = makeSolution(x, length, positions);
      solveSolution(transform, board, solution);
      minMoves = Math.min(minMoves, numMoves(solution));
    }
    return minMoves;
  }