c# -C语言在线考试系统-online judge端

前面介绍了考试系统学生端的功能:学生在线答题,提交答案,标注答案的状态为IsCompiling。

c#-asp net -C语言在线考试系统-考生端

https://blog.csdn.net/weixin_43917370/article/details/107790653

本篇介绍后台如何判题。


1、后台进程不断扫描solution表,取出答案状态为IsCompiling的那些

2、如果有编译错误,提示“不能生成exe”,如果能生成exe文件,转向第3步

3、对准备好的input数据,作为exe文件的输入,输出结果存入output文件

4、对比output文件和标准答案,如果完全相同,则accept,否则是答案错误,需要继续修改。

参考代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Diagnostics;
using System.Threading;
using System.Configuration;
using System.Data.SqlClient;
using System.IO;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {


                string userid = "11";
                string username = "11";
                String connetStr = ConfigurationManager.ConnectionStrings["ConsoleApplication4.Properties.Settings.ExamConnectionString"].ConnectionString.ToString();
                ExamDataClassesDataContext lqDB = new ExamDataClassesDataContext(connetStr);
                var result = from r in lqDB.cmdb_solution
                             where r.CompileInfor=="IsCompiling"

                             select r;
                //where r.userid == userid && r.username == username
                if (result.Count() > 0)
                {
                    //textBox1.Text = result.Count().ToString() + "\r\n";

                    foreach (cmdb_solution row in result)
                    {
                        //textBox1.Text = row.username + "  " + row.userid + "  " + row.DB_prob_id + "\r\n";
                        Judge(row);
                    }
                }
                //return;
            }

        }
        static void Judge(cmdb_solution row)
        {
            string stu_ans = row.stu_ans;
            string userid = row.userid, DB_prob_id = row.DB_prob_id;
            

            Dictionary<string, string> res;
            res = compile_code_function(stu_ans, userid, DB_prob_id); //源代码
            Console.WriteLine("{0} {1} {2}", userid, DB_prob_id, res["output"]);

            string CompileInfor2 = res["output"];

            String connetStr = ConfigurationManager.ConnectionStrings["ConsoleApplication4.Properties.Settings.ExamConnectionString"].ConnectionString.ToString();
            ExamDataClassesDataContext lqDB = new ExamDataClassesDataContext(connetStr);

            var result = from r in lqDB.cmdb_solution
                         where r.userid == userid && r.DB_prob_id == DB_prob_id
                         select r;

            //Console.WriteLine(CompileInfor2.IndexOf("AcceptAccepted"));
            if (CompileInfor2.IndexOf("AcceptedAccepted") >-1)
            {


                foreach (cmdb_solution row2 in result)
                {
                    row2.stu_score = row2.pro_score;                    
                    row2.CompileInfor = CompileInfor2;
                    break;
                }

            }
            else
            {
                foreach (cmdb_solution row2 in result)
                {
                    row2.stu_score = 0;
                    row2.CompileInfor = CompileInfor2;
                    break;
                }
            }
            lqDB.SubmitChanges();

        }

        //根目录
        static string rootPath = Directory.GetCurrentDirectory();
        //测试目录为根目录下的:000tmp
        static string tmp_dir_path = rootPath + "\\000tmp\\";
        //下面是编译程序的全路径,相对目录
        //exec_cmd = r'MinGW64/bin/x86_64-w64-mingw32-gcc.exe'
        //exec_cmd = r'MinGW64/bin/x86_64-w64-mingw32-g++.exe'
        static string exec_cmd = rootPath + "\\MinGW64\\bin\\x86_64-w64-mingw32-g++.exe";

        static Dictionary<string, string> compile_code_function(string stu_ans, string userid, string DB_prob_id)
        {
            Dictionary<string, string> res = new Dictionary<string, string>();
            res = zztPreCompile(stu_ans);

            //textBox1.Text += res["output"] + "\r\n";
            if (res["code"] == "0")//预编译,代码中有明显问题,例如使用宏
                return res;

            res = zztCompile(stu_ans, userid, DB_prob_id);
            //textBox1.Text += res["output"] + "\r\n";
            if (res["code"] == "0")//编译错误
                return res;

            //return res;

            // 编译成功,也有可能不能生成exe

            string exefile = tmp_dir_path + userid + "_" + DB_prob_id + "a.exe";
            if (File.Exists(exefile))
            {//文件存在,运行,用数据测试
                res = zztRun(userid, DB_prob_id);//
                return res;
            }
            else
            {
                res["code"] = "0";
                res["output"] = "生成exe失败!!";
                return res;

            }
        }

        static Dictionary<string, string> zztPreCompile(string stu_ans)
        {
            Dictionary<string, string> res = new Dictionary<string, string>();
            if (stu_ans == null)
            {
                res["code"] = "0";
                res["output"] = "缺main函数";
                return res;
            }
            if (stu_ans.IndexOf("main") < 0)
            {
                res["code"] = "0";
                res["output"] = "缺main函数";
                return res;
            }

            if (stu_ans.IndexOf("define") >= 0)
            {
                res["code"] = "0";
                res["output"] = "请不要使用define语句";
                return res;
            }

            if (stu_ans.IndexOf("fork") >= 0)
            {
                res["code"] = "0";
                res["output"] = "恶意代码错误";
                return res;
            }

            if (stu_ans.IndexOf("system") >= 0)
            {
                res["code"] = "0";
                res["output"] = "恶意代码错误";
                return res;
            }

            if (stu_ans.IndexOf("shut") >= 0)
            {
                res["code"] = "0";
                res["output"] = "恶意代码错误";
                return res;
            }

            res["code"] = "1";
            res["output"] = "预编译通过!";
            return res;

        }

        static Dictionary<string, string> zztCompile(string stu_ans, string userid, string pb_id)
        {//编译函数
            Dictionary<string, string> res = new Dictionary<string, string>();
            string c_file_name = tmp_dir_path + userid + "_" + pb_id + ".c";

            
            try
            {//保存源文件
                StreamWriter sw = new StreamWriter(c_file_name);
                sw.Write(stu_ans);
                sw.Close();

            }
            catch (IOException ex)
            {
                
                res["code"] = "0";
                res["output"] = "Create Code File Failing!";
                Console.WriteLine(ex.Message);
                return res;

            }

            string exe_file_name = tmp_dir_path + userid + "_" + pb_id + "a";
            string cmdStr = exec_cmd + " " + c_file_name + "  -o " + exe_file_name;  //##'-o' 一定得是小写

            Process p = new Process();
            //设定程序名
            p.StartInfo.FileName = "cmd.exe";
            //关闭Shell的使用
            p.StartInfo.UseShellExecute = false;
            //重定向标准输入
            p.StartInfo.RedirectStandardInput = true;
            //重定向标准输出
            p.StartInfo.RedirectStandardOutput = true;
            //重定向错误输出
            p.StartInfo.RedirectStandardError = true;
            //设置不显示窗口
            p.StartInfo.CreateNoWindow = true;

            string strPath = cmdStr;

            //textBox1.Text += strPath + "\n\r";
            p.Start();
            // 切换到test目录下
            //p.StandardInput.WriteLine("cd test");
            //执行gcc命令
            p.StandardInput.WriteLine(strPath);

            // 等待编译完成
            Thread.Sleep(500);
            p.StandardInput.WriteLine("exit");  //  退出
            //string str = p.StandardOutput.ReadToEnd();   //  cmd显示的字符串,放入str中
            string str = p.StandardError.ReadToEnd();//compile error

            //textBox1.Text += "compile result:" + str + "\r\n";

            p.Close();
            p.Dispose();
            File.Delete(c_file_name);//删除生成的源代码文件

            //textBox1.Text += "exe:" + exe_file_name + "\r\n";//exe_file_name has no .exe

            if (File.Exists(exe_file_name + ".exe"))
            {
                res["code"] = "1";
                res["output"] = "编译成功";
                return res;
            }
            else
            {
                res["code"] = "0";
                //res["output"] = str+"未生成exe文件";
                res["output"] = "编译错误,未生成exe文件";
                return res;
            }



        }

        //static string rootPath = Directory.GetCurrentDirectory();
        //测试目录为根目录下的:000tmp
        //string tmp_dir_path = rootPath + "\\000tmp\\";


        static Dictionary<string, string> zztRun(string userid, string pb_id)
        {//运行程序、测试数据
            Dictionary<string, string> res = new Dictionary<string, string>();

            // 文件重定向,用的管道
            //需要把数据文件整理好


            Process p = new Process();
            //设定程序名
            p.StartInfo.FileName = "cmd.exe";
            //关闭Shell的使用
            p.StartInfo.UseShellExecute = false;
            //重定向标准输入
            p.StartInfo.RedirectStandardInput = true;
            //重定向标准输出
            p.StartInfo.RedirectStandardOutput = true;
            //重定向错误输出
            p.StartInfo.RedirectStandardError = true;
            //设置不显示窗口
            //p.StartInfo.CreateNoWindow = true;  

            string data_dir_path = rootPath + "\\Data\\" + pb_id + @"\";

            string input_file_name = data_dir_path + @"in.txt";
            string answer_fime_name = data_dir_path + @"answer.txt";
            string stu_answer_fime_name = rootPath + "\\000tmp\\" + userid + "_" + pb_id + @"useranswer.txt";
            string exe_file_name = rootPath + "\\000tmp\\" + userid + "_" + pb_id + "a.exe";

            string cmd_str = exe_file_name + " < " + input_file_name + " > " + stu_answer_fime_name;


            p.Start();
            p.StandardInput.WriteLine(cmd_str);
            // 检查生成的myout.txt 和 指定的out.txt的数据对比
            //p.StandardInput.WriteLine("FC myout.txt out.txt");
            //p.StandardInput.WriteLine("exit");  //  退出
            Thread.Sleep(500);
            p.StandardInput.WriteLine("exit");  //  退出
                                                //string str = p.StandardOutput.ReadToEnd();   //  cmd显示的字符串,放入str中


            //下面比较学生答案和标准答案
            StreamReader fanswer = new StreamReader(answer_fime_name, Encoding.Default);
            StreamReader fstu_answer = new StreamReader(stu_answer_fime_name, Encoding.Default);
            string curr;
            string user;
            char[] ch = { ' ', '\r', '\n' };
            curr = fanswer.ReadToEnd();
            fanswer.Close();

            user = fstu_answer.ReadToEnd();
            fstu_answer.Close();
            curr = curr.TrimEnd(ch);
            user = user.TrimEnd(ch);

            //textBox1.Text += curr + "\r\n";
            //textBox1.Text += user + "\r\n";

            if (user == curr)
            {
                res["code"] = "1";
                //res["output"] = str+"未生成exe文件";
                res["output"] = "AcceptedAccepted";
                //textBox1.Text += res["output"] + "\r\n";


            }
            else
            {
                res["code"] = "0";
                res["output"] = "请继续修改";
                //textBox1.Text += res["output"] + "\r\n";

            }


            //textBox1.Text += "\r\n"+(p.ExitTime - p.StartTime).ToString() + "\r\n";

            p.Close();
            p.Dispose();

            //删除.c,.exe,*.txt
            File.Delete(exe_file_name);
            File.Delete(stu_answer_fime_name);


            return res;

        }
    }
}

1、ConsoleApplication4.exe是后台判题程序

2、MinGW64是C、C++编译器

3、Data对应每道题的input数据、标准答案

 

G0005是试题编号,对应文件夹内是input、answer。

4、 

生成的exe文件、output文件存中oootmp目录下。 

猜你喜欢

转载自blog.csdn.net/weixin_43917370/article/details/107794767
今日推荐