现在的位置: 首页 > 综合 > 正文

考场自动安排工具开发手记

2012年06月03日 ⁄ 综合 ⁄ 共 5629字 ⁄ 字号 评论关闭

    昨天教务的一个同事,提出有没有办法可以对169门考试(合计1744个学生)进行考试安排。因为是期末考试补考。因此其中很多考试存在学生冲突现象。

例如:

(英语翻译2-2<--->英语听力4-4) ID:200616031109
(英语专业四级培训-3<--->英语听力4-4) ID:200616031133
(英语翻译2-2<--->英语听力4-4) ID:200616031109
(英语专业四级培训-3<--->英语听力4-4) ID:200616031133
(英语翻译2-2<--->英语听力4-4) ID:200616031109
(英语专业四级培训-3<--->英语听力4-4) ID:200616031133
(英语听说2-2<--->大学英语听说4-2) ID:200616013260
(英语听说2-2<--->合同法案例实践-2) ID:200616041257

 

存在冲突的考试科目就不能安排在同一批次(也就是同一时间段内)

 

软件界面如图:

 考场自动安排软件

软件工作流程:

(1)导入CSV数据文件。

    文件格式为:

      [学号]-[姓名]-[考试科目]

    CSV文件导入代码:

        /// <summary>
        /// 将csv格式文件导成dataset
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="fileName">文件名</param>
        /// <returns></returns>
        public DataSet getCsv(string filePath, string fileName)
        {
            string strConn = "Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq=";
            strConn += filePath;
            strConn += ";Extensions=asc,csv,tab,txt;";
            OdbcConnection con = new OdbcConnection(strConn);
            DataSet data = new DataSet();
            string sql = "select * from " + fileName;
            OdbcDataAdapter adp = new OdbcDataAdapter(sql, con);
            con.Open();
            adp.Fill(data, "csv");

            return data;
        }

(2)把导入的数据进行处理。

    处理过程采用面向对象的思想,建立了一个考试类。

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace ExamManager
{
   public class Exam
    {
       public class student
       {
           public string studentID;
           public string studentName;
       }
       public string ExamName;//考试科目
       public string ExamTime;//考试时间
       public int Students;//学生数

       public ArrayList StudentList = new ArrayList(); //学生列表

       public void addStudent(string studentID,string studentName)
       {
           student s = new student();
           s.studentID = studentID;
           s.studentName = studentName;

           StudentList.Add(s);
       }

       public bool CheckStudentIdList(int N_PC,Exam ex,ref StringBuilder sb_ct)
       {
           ArrayList studIdList = ex.StudentList;

           for (int i = 0; i < studIdList.Count; i++)
           {
               for (int j = 0; j < StudentList.Count; j++)
               {
                   //考生 冲突
                   if (((student)studIdList[i]).studentID == ((student)StudentList[j]).studentID)
                   {
                       //Console.WriteLine("冲突:(" + ex.ExamName + "<--->" + this.ExamName + ") ID:" + ((student)studIdList[i]).studentID);
                       sb_ct.Append("批次:"+N_PC.ToString()+ "  冲突:(" + ex.ExamName + "<--->" + this.ExamName + ") ID:" + ((student)studIdList[i]).studentID);
                       sb_ct.Append("/r/n");
                       return false;
                   }
               }
           }

           return true;
       }
     
    }
}

该类主要负责将CSV文件进行处理,把同一考试科目的学生归集到一起。其次是负责将2个考试对象进行检测,看看是否存在冲突。算法采用双重循环,效率较低。呵呵

 

(3)考试安排

  public void KSAP()
        {
            //安排考试
            ks_pc.Clear();//
            Hashtable tmp = (Hashtable)htExams.Clone();
            int i = 0;
            int N_PC = 0;//批次

            StringBuilder sb = new StringBuilder();
            StringBuilder sb_ct = new StringBuilder();//冲突

        loop:
            foreach (DictionaryEntry ht in tmp)
            {
                if (i > int.Parse(txtKM_MAX.Text))
                {
                    i = 0;
                    N_PC++;
                }

                //从 考试表中 取出1个
                Exam e = (Exam)ht.Value;
                object obj = ks_pc[N_PC];
                if (obj == null)
                {
                    //单前批次还没添加过,直接添加 当前考试
                    ArrayList al = new ArrayList();
                    ks_pc[N_PC] = al;
                    al.Add(e);
                    tmp.Remove(ht.Key);//移除单前考试,不在加入
                   
                    i++;
                    sb.Append("/r/n----------------------------------/r/n");
                    //Console.WriteLine("New N_PC=" + N_PC.ToString() + " Exam:" + e.ExamName);
                    sb.Append("批次=" + N_PC.ToString() + "   Exam:" + e.ExamName+"  人数:"+e.StudentList.Count);
                    sb.Append("/r/n");
                    goto loop;
                }

                //sb_ct.Append("/r/n----------------" + N_PC.ToString() + "--------------/r/n");
                bool flag = true;
                ArrayList ks = (ArrayList)obj; //获取考试列表               
                for (int j = 0; j < ks.Count; j++)
                {
                    //开始检测
                    Exam le = (Exam)ks[j];

                    if (le.CheckStudentIdList(N_PC,e, ref sb_ct) == false)
                    {
                        //发现 冲突,不能将该考试添加进去
                        flag = false;//跳过该考试
                    }
                   
                }

                if (flag == true)
                {
                    //不存在冲突,可以添加进去
                    ks.Add(e);
                    tmp.Remove(ht.Key);
                    i++;
                    //Console.WriteLine("N_PC=" + N_PC.ToString() + " Exam:" + e.ExamName);
                    sb.Append("批次=" + N_PC.ToString() + "   Exam:" + e.ExamName + "  人数:" + e.StudentList.Count);
                    sb.Append("/r/n");
                    goto loop;
                }
               
            }

            if (tmp.Count > 0)
            {
                N_PC++;
                goto loop;
            }

            //汇总信息
            sb.Append("----------------------------------/r/n");
            for (int N = 0; N <= N_PC; N++)
            {
                ArrayList ks=(ArrayList)ks_pc[N];
                int num = 0;
                for (int j = 0; j < ks.Count; j++)
                {
                    //开始检测
                    Exam le = (Exam)ks[j];
                    num += le.StudentList.Count;
                }

                sb.Append("批次:" + N.ToString() + " 总人数=" + num.ToString() + "/r/n");
            }
            sb.Append("----------------------------------");
            txtMSG.Text = sb.ToString();
            txtCT.Text = sb_ct.ToString();

        }

考试安排也是采用了循环+goto 实现,根据预先设置好的同一批次科目数,将不存在冲突的考试科目安排在一起。

 

 

整个程序的源代码,在共享里,欢迎大家交流。多多提出意见。

抱歉!评论已关闭.