使用VC 开发考场随机排座系统
1、引言
随着国内高等教育信息化的推进,办公自动化等现代信息技术的广泛应用,考试管理的信息化方面也有了长足的发展。大部分的院系在考试过程中为了做到严格纪律,都纷纷采用了随机排座机制来保障考试的顺利进行。但是,传统的随机座号机制是通过考前人工排序或在考场内随机抽号的方式进行的,这就耗费了大量的人力和时间,造成效率低下,为此,我们开发了一个简单的考场随机排座系统。
2、设计内容
根据考场随机排座的要求,整个系统由以下的模块组成:数据导入、排序处理、打印输出。除此之外,还要求系统具有良好的人机界面。
数据导入工作的对象是欲排序的名单,由于大部分的学生信息采用EXCEL格式或者WORD文档格式进行存储,所以,首要的工作是要将这些格式文档读入排座系统。
对于排座系统中各个记录的随机排序,应避免VC 中伪随机数机制可能带来的影响,为每条记录分配一个真正的符合数学规律的随机值。
数据的输出部分包括模拟显示和打印两部分,将对随机排序后的结果进行输出,生成考场座次表,和试卷一起密封,方便监考人员在考试之前进行宣读。
软件系统主要采用VC 6.0编写,整个系统是基于对话框的应用程序,程序的主界面采用了列表视图控件,打印和显示部分则利用了MFC的打印机制。
3、关键技术
3.1数据导入
由于每一个考生在入学时就已经在学院的管理系统中具有了相应的信息,只需要将该信息导入排座系统即可,也可以通过人工的方式进行录入,本系统支持EXCEL和TXT两种格式的数据导入。EXCEL格式的考生信息导入排座系统的方法主要有两种:一种是通过ODBC数据接口对EXCEL格式的文件进行读取[1],该方法需要熟悉SQL语法和数据库操作的相关知识,文献[1]介绍了该方法的详细操作步骤;另一种方法则是利用工具软件XLS Converter先将EXCEL格式的文件转换为TXT文件[2],然后再利用VC本身的文件操作函数进行读取,本系统采用了这种方法,即利用VC调用文件转换引擎将EXCEL转换为TXT格式。实现的部分核心代码如下:
cmdline=exePath "XLSConverter.exe " "C:/tempXLS/temp.xls" " txt C:/tempXLS";
char buf[1024],cmdll[1024];
sprintf(cmdll,"%s",cmdline);
cmdll[sizeof(cmdll)-1]=0;
sprintf(buf,"%s","XLSConverter.exe");
buf[sizeof(buf)-1] = 0;
//通过在新的进程中以命令形式调用转换引擎XLSConverter.exe
STARTUPINFO startInfo;
startInfo.cb = sizeof(STARTUPINFO);
startInfo.lpReserved = NULL;
startInfo.lpTitle = buf;
startInfo.lpDesktop = NULL;
startInfo.dwX = 0;
startInfo.dwY = 0;
startInfo.dwXSize = 0;
startInfo.dwYSize = 0;
startInfo.dwXCountChars = 0;
startInfo.dwYCountChars = 0;
startInfo.dwFlags = STARTF_USESTDHANDLES;
startInfo.wShowWindow = 0; //SW_SHOWDEFAULT;
startInfo.lpReserved2 = NULL;
startInfo.cbReserved2 = 0;
startInfo.hStdInput = 0;
startInfo.hStdOutput = 0;
startInfo.hStdError = 0;
//产生新的进程,运行命令行,调用转换引擎进行转换
int nRet=CreateProcess(
NULL,
cmdll,
NULL,
NULL,
TRUE,
0, //CREATE_NEW_CONSOLE
NULL,
NULL,
&startInfo,
&pidInfo);
if(!nRet)
{
AfxMessageBox("调用引擎失败,程序将退出!",MB_OK|MB_ICONSTOP);
return -1;
}
DWORD dwWait=WaitForSingleObject(pidInfo.hProcess, INFINITE); //等待进程结束
return;
3.2随机数的产生
随机数的产生需要一个随机的种子,而计算机产生的随机数是通过递推的方法得到的,必须有一个初始值,也就是通常所说的随机种子,如果不对随机种子进行初始化,那么计算机有一个缺省的随机种子,这样每次产生的随机数序列结果就会完全相同,在VC系统中,随机种子的初始化是通过srand(int)函数进行的,但是如果给定的参数是一个常量,则每次得到的随机数序列也会完全相同,即使是使用系统时间作为随机种子进行初始化srand(GetTickCount()),又不能在每次调用rand()的时候都进行这项操作,因为现在计算机上运行速度比较快,当连续调用rand()函数时,系统的时间还没有更新,这也不足以保证产生随机数序列的真正随机性。
本系统采用了对产生的随机数序列进行筛选的方法,使得产生的随机数序列符合一维正态分布的概率密度函数规律,其原理为:若一个数列服从一维正态分布,那么它的概率密度函数为(其中,为常数,分别代表数学期望和方差[3]),根据一维正态分布的概率密度理论为随机数序列的均值,代表着随机数在该处的概率最大,为方差,代表产生的随机数偏离均值的程度,其概率密度函数曲线如图1所示,利用rand()函数线性变换后产生的平均随机数,带入该函数模型进行验证,若随机数的函数值在曲线范围内,即认为该随机数符合条件,进行保留,反之,舍弃;基于该方法产生的10000个随机数序列的统计如图2所示,从图2可以看出随机数序列符合一维正态分布的规律,达到系统所需的随机数要求。
产生随机数的核心代码如下:
//产生有四位小数的min和max之间的一个随机数
double CRandomGen::AverageRandom(double min, double max)
{
int minInteger = (int)(min*10000);
int maxInteger = (int)(max*10000);
int randInteger = rand()*rand();
int diffInteger = maxInteger - minInteger;
int resultInteger = randInteger % diffInteger minInteger;
return resultInteger/10000.0;
}
//计算给定随机数的一位正态分布函数值
double CRandomGen::Normal(double x, double miu, double sigma)
{
return 1.0/(sqrt(2*PI)*sigma)* exp(-1*(x-miu)*(x-miu)/(2*sigma*sigma));
}
//对产生的随机数进行筛选
double CRandomGen::NormalRandom(double miu, double sigma, double min, double max)
{
double x;
double dScope;
double y;
do
{
x = AverageRandom(min,max);
y = Normal(x, miu, sigma);
dScope = AverageRandom(0, Normal(miu,miu,sigma));
}while( dScope > y);
return x;
}
3.3打印处理
由于整个系统采用了基于对话框的应用程序结构,而基于对话框的应用程序本身不具有文档/视图结构,对打印功能的支持有限,所以整个打印处理部分也需要自定义解决,本系统采用了生成临时CFrameWnd和CView类对象的方法[4]调用系统默认的OnFilePrintPreview()函数来实现打印功能,文献[4]对此有详细描述。
4 结束语
本系统运行后的界面如图3所示,通过该系统可以很方便地实现对考生随机座号的生成,同时,系统提供的丰富的打印预览和打印功能也为数据的输出提供了便利,如图4。
图3 程序运行主界面
图4 打印功能模块界面
本系统是根据高校考试的需求,结合高校学生信息管理的特点开发的,整个系统具有良好的实用性和可扩充性,已经应用于院系的考试中,能满足院系环境下的考试管理需求,使用该系统一方面可以减少相关教务和教学管理人员的工作量和劳动强度,增加工作效率,另一方面也提高了考试管理信息化的水平,使得考试管理工作上了一个新的台阶,具有非常好的通用性和推广价值。