一个用来对拍和生成随机数据的程序(Windows平台)。
A tool for OIer to generate random input and compare the result of two programs (in Windows).
这个项目是用Visual Studio 2017写的,所以克隆这个项目后用Visual Studio打开Judger.sln,按生成解决方案即可。
确保你的文件夹中有
- 你要对拍的程序
- 正确的程序(建议:把正确的程序命名为带force或者ac的名字,这样Judger.exe更容易识别出要对拍的程序。)
- 生成数据的程序
将Judger.exe放到你要对拍的程序的目录下,运行Judger.exe,按空格使用生成向导,然后按照向导的提示输入即可。
产生正确的JudgeInfo.txt后,再次运行Judger.exe即可开始对拍。
对拍时可以按p
键暂停,按Alt+J
最小/最大化。当处于最小化时拍出错误或发生异常,Judger会自动弹出。
注意,每次修改JudgeInfo.txt后,请重新运行Judger.exe。
这个语言用于快速、便捷地生成随机数据,从而不用专门去写一个生成数据的程序。当然,这套简单的语言并不能产生有特殊要求的数据,这时候还是只能专门写一个生成数据的程序。
首先,这个部分请写在input:
下。
这个语言很简单,你输入的大部分字符都是直接输出的。比如你的input部分如下:
input:
// I am notes.
I want this string.\n
But you don't
want this string.
那么你的输入文件就会得到:
I want this string.
But you don't want this string.
正如你所见,输出换行用的是'\n',而在input:
中换行并没有什么用处。实际上,Judger在处理这段语言时会把所有行拼接到一行中,所以你可以随心所欲的换行而不会影响输出。
在input:
里你也可以写注释,不过请确保//
在行首。
当然,有些字符是不可以(或者不建议)直接输出的,比如'(',')','[',']','{','}',';',这时候你需要在它们之前加一个反斜杠'\'来输出它们。
这个语言只支持以一个英文字母命名的变量,区分大小写,共52个。
使用变量的基本形式是x(expr1)
或x(expr1, expr2)
(变量与左括号之间不能有空格,否则会被Judger视为普通字符直接输出),其中x是变量名,expr1和expr2是表达式,表达式中可以含有变量(详见表达式小节)。前一种形式是将expr1的值赋给x,后一种形式是随机产生一个在[expr1, expr2](或[expr2, expr1],视两个表达式的结果大小而定)的整数赋给x。未初始化的变量值未知。
正常情况下,变量是默认输出的。你也可以用x()
直接输出变量x的值而不进行赋值。如果你有变量不想输出,可以在变量与左括号之间插入'$',即x$(expr1)
或x$(expr1, expr2)
。
注意:变量小写字母c
是特殊的、专门用来输出字符的变量,其输出的是变量值对应的ASCII码表中的字符。
在这个语言的表达式中,运算数可以是数字(范围在long long以内),变量和字符常量(比如'a'
,等价于输入了数字97)。
运算符有以下9种,都是二元运算符:
- a+b:返回a与b的和
- a-b:返回a与b的差
- a*b:返回a与b的积
- a/b:返回a与b的商(整数除法)
- a<b:返回a与b的较小值
- a>b:返回a与b的较大值
- a^b:返回a的b次方
- a%b:返回a模b
- a=b:若a与b相等则返回1,否则返回0
运算符的优先级(编号越小优先级越高):
'(',')'
'^'
'*','/','%'
'+','-'
'<','>'
'='
运算时同优先级的运算符采用左结合的方式。
循环语句有三种用法:
[expr]body;
,其中expr是表达式,其值代表循环的次数,body是循环体,最后用分号结束。[expr,varible]body;
,其中varible是变量名,这样写声明了varible是循环变量,它从1开始,每次循环结束后+1。你可以在循环体内部任意的改动varible的值,这不会影响循环的次数。其余同1。[expr,varible,start_value]body;
,其中start_value是变量的初始值。其余同2。
循环语句可以嵌套。
选择语句的格式是{block_1|block_2|...|block_n}
,在执行时,它会随机选择一个block来执行。
选择语句允许嵌套,也可以和循环语句嵌套。
input:
// 假设输入中的权值最大是2*10^18,该变量仅方便使用,不输出
W$(2*10^18)
// 结点数和操作数
n(100000) m(100000)\n
// 每个结点有一个初始的权值
[n]a(1, W) ;\n
// 随机生成树边,期望深度log n
[n-1, i]u(1, i) v(i+1)\n;
// 生成m个操作,假设操作有两种:
// 1 u v:询问u到v的路径上的点的权值和
// 2 u v w: 对u到v的路径上的点的权值+w
[m]{1 u(1, n) v(1, n)|2 u(1, n) v(1, n) w(1, W)}\n;
如果你想要树的深度比较大,可以
input:
...
// 随机生成树边,深度在n/2量级
[n/2-1, i, 2]u(i-1) v(i)\n;
[n-n/2, i, n/2+1]u(1, i-1) v(i)\n;
...
input:
n(1, 100000)\n
// 找一个与n互质的数
W$(1000000007 % n)
// 偏移
D$(1, n)
[n, i, D]a(W * i % n + 1) ;\n
开启这个模式后,Judger不会再进行对拍,所以你只需确保生成数据的部分和你的程序是正确的。
如果你想利用Judger制作测试数据,那么请在JudgeInfo.txt里写下makedata:
。
这一部分可以由任意多行组成,其中每一行的格式是:
[-]n: Initialization
其中n是正整数,Initialization是由Judger的数据生成语言写成的初始化部分。
Judger会按顺序处理每一行。对于其中的一行,如果n前没有减号,那么这一行会告诉Judger要生成n组数据,然后在生成每组数据时,先执行Initialization,再调用input:
下的代码(或者你的输入生成程序,如果你用的是Judger提供的模板,你会看到Judger传进来一个代表现在生成的数据是第几组的参数dataId)。如果n前有减号,那么表示生成至第n组数据,其他部分是一样的。
注意:Initializatio中的代码不会输出! 也就是说,你初始化的时候可以这样写
makedata:
10: n(100000) m(10^6)
但Judger在处理这一段时不会输出空格以及n,m的值。