c++编写评测机(2)

目录

前言

完善过程

如何自定义头文件与名字空间

完整代码

后续透露


前言

前几天刚刚写完了c++编写评测机(1),今天又来更2了。这更新速度,必须来个三连啊。

评测机1.0.0版本中还有很多可以优化的部分,比如:刚打开就进行评测,评测完要再次运行才能继续评测,无法选择忽略空格与换行,没有标程的情况下无法评测。v1.0.1对其中一部分进行了完善。

v1.0.1版本的评测机主要更新了以下内容:

  1. 优化了软件界面,可以多次重复评测。
  2. 可以选择对拍时忽略与不忽略空格,忽略与不忽略换行。
  3. 将一些杂七杂八的函数写到一个头文件里。

完善过程

1.针对评测机刚运行就进行评测,评测完要再次运行才能继续第二次评测的问题,我们可以在程序最外层加上while(1)死循环,并且只有输入1才进行评测,评测结束后输入0回到主页可以再次评测。这是优化后的部分代码:

while(1){
		Clear_Qiuckedit();
		hide();
		gotoxy(1, 1);
		printf("1:评测 2:设置\n");
		char choose = getch();
		if(choose == '1'){
			system("cls");
			if(!initialize()){
				printf("0:返回\n");
				Mypause('0');
				continue;
			}
			start_judge();
			printf("0:返回\n");
			Mypause('0');
			continue;
		}
}

2.针对评测时的对拍方式,我们可以在主页增加一个选项,就是输入2即可进入设置。设置也有两种,一种是选择是否忽略空格,一种是选择是否忽略换行。并且后面还配有“√”与“-”进行图形化展示选项。在评测时,只要注意对ans.out和std.out中的字符串进行按照评测室的选项特殊处理就好了。代码如下:

else if(choose == '2'){
			while(1){
				system("cls");
				printf("0:返回\n1:评测方式\n2:比较方式\n");
				char choosea = getch();
				if(choosea == '1'){
					system("cls");
                    printf("暂不支持\n0:返回\n");
                    Mypause('0');
				}else if(choosea == '2'){
					while(1){
						system("cls");
						printf("0:返回\n1:忽略空格");
						if(ifblank){
							printf("-\n");
						}else{
							printf("√\n");
						}
						printf("2:忽略换行");
						if(ifenter){
							printf("-\n");
						}else{
							printf("√\n");
						}
						char choose2 = getch();
						if(choose2 == '1') ifblank = !ifblank;
						else if(choose2 == '2') ifenter = !ifenter;
						else if(choose2 == '0'){
							system("cls");
							break;
						}
					}
				}else if(choosea == '0'){
					system("cls");
					break;
				}
			}
		}

可以看到,这里又用到了while(1),这样可以避免选择完后立即回到主页,想要选择就得再次点击”“设置”的尴尬情况。

对于后续的字符串处理,我们可以通过删除的方式忽略空格或换行符,具体看代码:

void enter_deal(const char* filename, bool ifblank = 1, bool ifenter = 1){
	int i, j = 0;
	char s[10000];
	FILE *p;
    p = fopen(filename, "r");
    fscanf(p, "%[^$]", s);
    fclose(p);
    for(int i = 0; i < strlen(s); i++){
        if((!ifblank && s[i] == ' ') || (!ifenter && s[i] == '\n'))
			continue;
        s[j++] = s[i];
    }
    s[j] = 0;
	p = fopen(filename, "w");
    fprintf(p, "%s", s);
    fclose(p);
    return;
}

其中ifblank变量指的是是否忽略空格,ifenter变量指的是是否忽略换行。特别注明:换行符是‘\n',占一个字符,和‘a’、‘b'等一样可以操作,只不过电脑输出时是以换行的方式呈现的。

3.可以看到,现在的代码函数已经非常多了,为了方便后续的更改,我们把这些函数放入一个头文件‘tool.h’里。把自定义的变量放入自己的名字空间内。下面介绍如何自定义头文件与名字空间。

如何自定义头文件与名字空间

博主写这个评测机的目的就是为了学习嘛,所以与评测机无关的东西可能有点多。

1.如何自定义与使用头文件。

我们只需要新建一个文件,然后在里面放入如下代码

#ifndef TOOLS_H
#define TOOLS_H

#endif

其中TOOLS_H中的TOOLS是头文件名称,大小写随意。

然后在中间编写正常的程序,一般只在头文件中写函数,变量与宏最好不要写进去。不过博主为了代码美观,将变量放到一个名字空间中放入头文件。变量与宏不写进头文件的主要原因是可能在引用头文件的程序中使用了重复的变量名或宏,但由于评测机.cpp中没有任何变量,所以可以放心写进头文件中。

那么自定义头文件该怎么用呢?有静态和动态链接两种方式,本文只讲静态。将头文件命名为XXX.h,注意:一定是.h,然后引用时写成include"XXX.h",例如本文就写成include"tools.h"。这样就可以在程序中引用头文件中的函数啦。

2.如何自定义名字空间。

大家最常用的名字空间就是std了,不过它也可以自己定义。

定义方法如下:namespace 名字空间的名称。用时写成:using namespace 名字空间的名称。并且多个名字空间可以同时引用。例如:

namespace mname{
	char textpoint[10000];
	struct node{
		int time_limit, point;
	}sample[1005];
	int cnt, mysco, totlesco;
	int outcheck_std, outcheck_ans;
	const int maxn = 100005;
	char ANS[maxn], STD[maxn] = "";
	clock_t start, end;
	double elapsed_secs;
	const char *name1 = "test.in";
	string samplename = "sample";
	bool ifblank = 1, ifenter = 1;
}
using namespace mname;

完整代码

知道了如何完善后,大家可以自己动手完善。不过我还是会附上源码,毕竟(有白嫖怪)这是个开源项目嘛。

评测机.cpp

//v1.0.2
#include"tools.h"
int main(){
	color(7);
	while(1){
		Clear_Qiuckedit();
		hide();
		gotoxy(1, 1);
		printf("1:评测 2:设置\n");
		char choose = getch();
		if(choose == '1'){
			system("cls");
			if(!initialize()){
				printf("0:返回\n");
				Mypause('0');
				continue;
			}
			start_judge();
			printf("0:返回\n");
			Mypause('0');
			continue;
		}
		else if(choose == '2'){
			while(1){
				system("cls");
				printf("0:返回\n1:评测方式\n2:比较方式\n");
				char choosea = getch();
				if(choosea == '1'){
					system("cls");
                    printf("暂不支持\n0:返回\n");
                    Mypause('0');
				}else if(choosea == '2'){
					while(1){
						system("cls");
						printf("0:返回\n1:忽略空格");
						if(ifblank){
							printf("-\n");
						}else{
							printf("√\n");
						}
						printf("2:忽略换行");
						if(ifenter){
							printf("-\n");
						}else{
							printf("√\n");
						}
						char choose2 = getch();
						if(choose2 == '1') ifblank = !ifblank;
						else if(choose2 == '2') ifenter = !ifenter;
						else if(choose2 == '0'){
							system("cls");
							break;
						}
					}
				}else if(choosea == '0'){
					system("cls");
					break;
				}
			}
		}
	}
	return 0;
}

tools.h

#ifndef TOOLS_H
#define TOOLS_H
#include<bits/stdc++.h>
#include<windows.h>
#include<conio.h>
#define WEXITSTATUS(status)   (((status) & 0xff00) >> 8)
#define WIFEXITED(status) ((status & 0x7f) == 0)
using namespace std;
namespace mname{
	char textpoint[10000];
	struct node{
		int time_limit, point;
	}sample[1005];
	int cnt, mysco, totlesco;
	int outcheck_std, outcheck_ans;
	const int maxn = 100005;
	char ANS[maxn], STD[maxn] = "";
	clock_t start, end;
	double elapsed_secs;
	const char *name1 = "test.in";
	string samplename = "sample";
	bool ifblank = 1, ifenter = 1;
}
using namespace mname;
void Clear_Qiuckedit(){
	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;
	SetConsoleMode(hStdin, mode);
}
void hide(int hide_type = 0){
	CONSOLE_CURSOR_INFO cursor_info = {1, hide_type};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
void color(int x, bool intensity = true){
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
    x | (intensity << 3));
}
void gotoxy(int x, int y){
	COORD pos = {y - 1, x - 1};
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void print(string s, int n){
	gotoxy(1, 1);
	cout << "状态:";
	color(n);
	cout << s << "          " << endl;
	color(7);
}
bool findfile(const char * find_filename){
	FILE *fp;
	fp = fopen(find_filename, "r");
	fclose(fp);
	return fp;
}
void enter_deal(const char* filename, bool ifblank = 1, bool ifenter = 1){
	int i, j = 0;
	char s[10000];
	FILE *p;
    p = fopen(filename, "r");
    fscanf(p, "%[^$]", s);
    fclose(p);
    for(int i = 0; i < strlen(s); i++){
        if((!ifblank && s[i] == ' ') || (!ifenter && s[i] == '\n'))
			continue;
        s[j++] = s[i];
    }
    s[j] = 0;
	p = fopen(filename, "w");
    fprintf(p, "%s", s);
    fclose(p);
    return;
}
bool compare(const char* filename1, const char* filename2){
	int i, j = 0;
	char s1[10000];
	FILE *p1;
    p1 = fopen(filename1, "r");
    fscanf(p1, "%[^$]", s1);
    fclose(p1);
	char s2[10000];
	FILE *p2;
    p2 = fopen(filename2, "r");
    fscanf(p2, "%[^$]", s2);
    fclose(p2);
    if(strlen(s1) != strlen(s2)) return false;
    for(int i = 0; i < strlen(s1); i++){
    	s1[j++] = s1[i];
    }
    j = 0;
    for(int i = 0; i < strlen(s1); i++){
    	s2[j++] = s2[i];
    }
    for(int i = 0; i < strlen(s1); i++){
        if(s1[i] != s2[i]) return false;
    }
    return true;
}
void getpoint(const char *filename){
	int i, j = 0;
	FILE *p;
    p = fopen(filename, "r");
    fscanf(p, "%[^$]", textpoint);
    fclose(p);
    for(int i = 0; i < strlen(textpoint); i++){
        textpoint[j++] = textpoint[i];
    }
    textpoint[j] = 0;
    int f;
	for(int i = 0; i < strlen(textpoint); i++){//获得测试点个数
		if(textpoint[i] == '#'){
			f = i;
			break;
		}
		if(textpoint[i] >= '0' && textpoint[i] <= '9')
			cnt = cnt * 10 + textpoint[i] - '0';
	}
	int now = 0;
	for(int i = f; i <= strlen(textpoint); i++){//获取测试点时间限制及分数
        if(textpoint[i] == '#'){
        	now++;
		}
		else if(textpoint[i] == ':'){
			int nowlimit = 0;
			for(int j = i; j <= strlen(textpoint); j++){
				if(textpoint[j] == ','){
					int nowpoint = 0;
                    for(int k = j; k <= strlen(textpoint); k++){
                    	if(textpoint[k] == '#'){
                    		break;
						}
						if(textpoint[k] <= '9' && textpoint[k] >= '0'){
							nowpoint = nowpoint * 10 + textpoint[k] - '0';
						}
					}
					sample[now].point = nowpoint;
					break;
				}
				if(textpoint[j] >= '0' && textpoint[j] <= '9') nowlimit = nowlimit * 10 + textpoint[j] - '0';
			}
			sample[now].time_limit = nowlimit;
		}
	}
}
void printsample(const char *filename, const char *filename2){
	int i, j = 0;
	char s[10000];
	FILE *p;
    p = fopen(filename, "r");
    fscanf(p, "%[^$]", s);
    fclose(p);
    for(int i = 0; i < strlen(s); i++){
        s[j++] = s[i];
    }
    s[j] = 0;
	p = fopen(filename2, "w");
    fprintf(p, "%s", s);
    fclose(p);
    return;
}
void judge(){
	for(int i = 1; i <= cnt; i++){
		totlesco += sample[i].point;
		cout << "#" << i << ": ";
	    char temp[10000];
	    sprintf(temp, "%d", i);
		string toname = samplename + temp + ".in";
		const char *name2 = toname.c_str();
		if(!findfile(name2)){
			cout << "未找到" << name2 << "!\n";
			continue;
		}
		printsample(name2, name1);
		outcheck_std = system("std.exe");
		start = clock();//
		outcheck_ans = system("ans.exe");
		end = clock();//
		elapsed_secs = static_cast<double>(end - start);//
		if(outcheck_std == -1 || outcheck_ans == -1 || WIFEXITED(outcheck_std) == false || WIFEXITED(outcheck_ans) == false || 0 != WEXITSTATUS(outcheck_std) || 0 != WEXITSTATUS(outcheck_ans)){
			color(5);
			cout << "RE";
			color(7);
			cout << "(" << elapsed_secs << "ms)\n";
			continue;
		}
		if(elapsed_secs > sample[i].time_limit){
			color(3);
			cout << "TLE";
			color(7);
			cout << "(" << elapsed_secs << "ms)\n";
			continue;
		}
		bool ifcontinue = 1;
		if(!findfile("ans.out")){
			cout << "未找到输出!\n";
			ifcontinue = 0;
		}
		if(!findfile("std.out")){
			cout << "未找到输出!\n";
			ifcontinue = 0;
		}
		if(!ifcontinue) continue;
		enter_deal("ans.out", ifblank, ifenter);
		enter_deal("std.out", ifblank, ifenter);
		int count_ans = 0, count_std = 0;
		freopen("std.out", "r", stdin);
			scanf("%s", STD);
		freopen("ans.out", "r", stdin);
			scanf("%s", ANS);
		if(compare("ans.out", "std.out")){
			color(2);
			cout << "AC";
			color(7);
			cout << "(" << elapsed_secs << "ms)\n";
			mysco += sample[i].point;
		}
		else{
			color(4);
			cout << "WA";
			color(7);
			cout << "(" << elapsed_secs << "ms)\n";
		}
	//	printf("Your answer:\n%s\nCorrect answer:\n%s\n", ANS, STD);//输出用户答案以及正确答案
	}
}
void start_judge(){
	getpoint("textpoint.txt");
	print("提交中", 7);
	int i = 0, j = 0;
//	freopen("report.out","w",stdout);
//	system("del ans.out");
//	system("del std.out");
//	system("del report.out");
//	system("del ans.exe");
//	system("del std.exe");
    gotoxy(1, 1);
    print("编译中", 7);
	if(sizeof(char*) == 4){
		int status_std32 = 0, status_ans32 = 0;
		status_std32 = system("g++ -o std.exe -m32 std.cpp");
		status_ans32 = system("g++ -o ans.exe -m32 ans.cpp");
		if(status_ans32 == -1 || status_std32 == -1 || WIFEXITED(status_ans32) == false || WIFEXITED(status_std32) == false || 0 != WEXITSTATUS(status_ans32) || 0 != WEXITSTATUS(status_std32)){
			print("CE", 6);
			return ;
		}
	}
	if(sizeof(char*) == 8){
		int status_std = 0, status_ans = 0;
		status_std = system("g++ -o std.exe std.cpp");
		status_ans = system("g++ -o ans.exe ans.cpp");
		if(status_ans == -1 || status_std == -1 || WIFEXITED(status_ans) == false || WIFEXITED(status_std) == false || 0 != WEXITSTATUS(status_ans) || 0 != WEXITSTATUS(status_std)){
			print("CE", 6);
			return ;
		}
	}
	print("评测中", 7);
	judge();
	print("评测结束", 7);
	gotoxy(cnt + 2, 1);
	cout << "分数:" << mysco << "(/" << totlesco << ")" << endl;
	printf("结果:");
	if(totlesco == mysco){
		color(2);
		printf("AC\n");
		color(7);
	}
	else{
		color(4);
		printf("WA\n");
		color(7);
	}
}
//void deletefile(){
//	system("del ans.exe");
//	system("del std.exe");
//	system("del ans.out");
//	system("del std.out");
//	system("del test.in");
//}
bool initialize(){
	bool back = 1;;
	if(!findfile("std.cpp")){
		printf("未找到std.cpp!\n");
		back = 0;
	}
	if(!findfile("ans.cpp")){
		printf("未找到源程序!\n");
		back = 0;
	}
	if(!findfile("textpoint.txt")){
		printf("请创建textpoin.txt并将测试点数据存入\n");
		back = 0;
	}
	cnt = 0;
	totlesco = 0;
	mysco = 0;
	return back;
}
void Mypause(char to){
	while(1){
		if(kbhit()){
			char ch = getch();
			if(ch == to){
				system("cls");
				break;
			}
		}
	}
}

使用方法除了多了一个头文件,其他和v1.0.0版本一样。

后续透露

下一个版本的改动比较大,主要是针对访问指定目录下文件进行性优化。给个三连,让我有更下去的动力~

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
1、系统和网络编程库:ACE 除了ACE之外,还有很多系统和网络编程方面的程序库。比如在线程库方面,还有ZThread、boost::thread,如果放大到C/C++领域,还有APR,还有CII。在文件和目录操作方面,boost也有相应的组件,而在网络编程方面有socket++,还有boost::asio,未来的C ++0X中几乎肯定有一个网络编程和一个线程库。然而目前看来,ACE仍然是进行系统和高性能网络编程的首选,其地位在一段时间内不会被撼动。它不但是一个实用的程序库、框架集,还是一个典范的设计模式应用范例,非常值得学习。 2、GUI库:Qt 传统上Qt被认为是可移植的GUI库,但实际上Qt现在已经是一个比较完整的可移植应用程序框架了,其中包含了大量的工具,比如正则表达式、Web和 Socket类、2D和3D图形、XML解析、SQL类等,甚至还包括了一个完整的容器类库,不过其王牌还是GUI。在目前的跨平台GUI框架中,Qt成熟度最高,已经被一些大公司应用在关键产品中。由于Trolltech对Qt采用的dual license模式,该产品既可以从开源社区获得支持,又能够赚取足够的商业利润,因此其前景也令人比较有信心。 Qt的主要技术特色是其元对象模型。Qt实际上使用的并不是标准的C++,而是标准C++的一个扩展。它通过元对象模型扩展,实现了著名的signal/slot制,而这一制也成为Qt的最大特色和优势。 与Qt类似的可移植GUI框架还有wxWidget、FOX等。 3、分布式对象中间件:ICE ICE是分布式对象中间件领域里的后起之秀,可以大致地将其视为“改进版”的CORBA。目前应用在一些大型项目当中,其中包括波音公司主持的下一代陆军作战系统。 ICE的一个特别价值是其代码的范例意义。由于ICE的出现较晚,开发者比较系统地应用了新的C++编程风格,所以成为了研读C++代码的良好目标。 4、正则表达式:boost::regex 正则表达式是编程工作中最强有力的工具之一。C++的正则表达式支持一直以来是一个软肋。大约在2001年左右,boost中出现了regex库,初步解决了这个问题。但是最初的regex无论在效率上还是可靠性方面都有一些问题,后来经过一次大规模的翻修之后,达到了比较完善的程度。 其他可以选择的替代品还有C语言的pcre库,Qt中的QRegExp类等。 5、矩阵计算:MTL 自1995年以来,C++在科学计算领域当中取得了巨大的突破。这主要归功于template技术的高级应用,使得C++在科学计算的性能方面取得了巨大的进步,一大批优秀的C++科学计算库涌现出来。比如Blitz++、POOMA、MTL、Boost::uBLAS。而这其中,MTL就功能丰富程度、性能、开发支持和成熟程度来讲,是比较突出的一个,因此可以优先考虑。值得一提的是,2002年,MTL与后来被Intel收购的KAI C++配合,曾经在性能评测中击败了FORTRAN。 6、XML、TinyXml C++的XML相关库不少,但是大部分其实都是C库,使用起来自然不那么轻便。其中基于DOM的有TinyXml,基于SAX的当然是Xerces。前者小巧快捷,便于使用,适合做数据交换。后者则是全功能的XML解析器。 7、内存管理:boost::smart_ptr,Hans-Boehm GC C/C++的内存管理是一个永恒的话题。一般来说,C++开发者倾向于自己管理内存。然而,出乎很多C++开发者意料的是,近期C++的一些领袖人物已经公开宣称,如果不配备自动内存管理制,用C++编写安全可靠的大型程序是非常困难的。而Bjarne Stroustrup也曾对中国开发者建议,如果没有特别的理由,应该在大型项目中使用自动内存管理工具。因此,今天的C++开发者应当积极地学习和应用自动内存管理设施。 说到自动内存管理,比较轻量级的做法是boost::smart_ptr,而激进的做法是引入完整的GC制。目前开源而又比较可靠的GC中,Hans- Boehm GC无疑是最受信赖的。作为一个保守的GC,Hans-Boehm GC在性能和功能方面都算是卓越。特别是,使用这个**,你仍然可以*elete、free来自己管理内存,对于我们编程习惯的冲击比较小。 8、配置管理:Lua 随着软件系统越来越复杂,对软件的可配置型提出了越来越高的要求。传统上只要通过命令行参数来配置的系统,现在可能需要越来越多的方式和制。目前越来越受欢迎、并且得到越来越多证实的做法,是将Lua嵌入到C/C++程序中,而用Lua程序作为配置脚本。这种做法的优势是,Lua语言强大灵活,可以适应复杂的配置要求。同时,Lua便于嵌入C/C++程序,而且编译执行速度非常快,可以说是目前解决C/C++程序配置管理问题的一个出色方案。 9、密码及安全:OpenSSL 安全是今天进行C/C++编程无法回避和必须重视的问题。然而编写安全的应用程序,特别是跟网络相关的C/C++应用程序,是一件十分困难的事情。可以说,整个业界目前在这个进程上仍然处于“初级阶段”。特别是涉及到大量的安全、密码学相关的算法、规范,如果让开发者自己摸索,其工作量和难度达到了不现实的程度。因此必须借助可靠的相关程序库才有可能提高程序的安全性。在这方面,OpenSSL是目前最好的选择,其内容之全面可靠,已经成为业界标杆。然而,由于安全编程固有的复杂性,即使使用penSSL,开发工作仍然是非常繁琐的。因此我们也希望能够尽快看到更简单、更易用的C/C++安全程序库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值