JudgeServer for NOJ, inspired by QDUOJ.
This package is available on Docker Hub and Github Container Registry.
You can download from Docker Hub:
docker pull njuptaaa/judge_server
Since v0.3.0
all version are pre-released on Github Container Registry then upload to Docker Hub later, thus you can download latest version from GHCR:
docker pull ghcr.io/njuptaaa/judge_server
You might want to specify a certain version of JudgeServer, for example, if you are using NOJ v0.18.0
, you need at least JudgeServer v0.3.1
for SPJ supporting libraries and Node.js compiler to function properly:
docker pull njuptaaa/judge_server:v0.3.1
You can download latest experimental build by using nightly
tag, they are latest for sure, but may contain developing features that your NOJ version does not currently support:
docker pull njuptaaa/judge_server:nightly
You can compile NOJ JudgeServer yourself.
docker build . -t njuptaaa/judge_server
If you are using networks that have limited internet access, you can try using proxy to build. In the following example we using a proxy located on port 1080 of your computer:
docker build . -t njuptaaa/judge_server --build-arg http_proxy=http://host.docker.internal:1080 --build-arg https_proxy=http://host.docker.internal:1080
If you are a resident of Chinese mainland, try using Dockerfile.cn
, it is pre-configured to use some mirroring service:
docker build . -f Dockerfile.cn -t njuptaaa/judge_server
NOJ JudgeServer is driven by Babel Extension NOJ, see Babel Extension NOJ and NOJ BABEL Github Public Mirror for more information.
Language | Compile/Run Command |
---|---|
C | /usr/bin/gcc -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c99 {src_path} -lm -o {exe_path} |
C 11 | /usr/bin/gcc -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c11 {src_path} -lm -o {exe_path} |
C++ | /usr/bin/g++ -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c++11 {src_path} -lm -o {exe_path} |
C++ 14 | /usr/bin/g++ -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c++14 {src_path} -lm -o {exe_path} |
C++ 17 | /usr/bin/g++ -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c++17 {src_path} -lm -o {exe_path} |
Java 8 | /usr/bin/javac8 {src_path} -d {exe_dir} -encoding UTF8 /usr/bin/java8 -cp {exe_dir} -XX:MaxRAM={max_memory}k -Djava.security.manager -Dfile.encoding=UTF-8 -Djava.security.policy==/etc/java_policy -Djava.awt.headless=true Main |
Java 17 | /usr/bin/javac17 {src_path} -d {exe_dir} -encoding UTF8 /usr/bin/java17 -cp {exe_dir} -XX:MaxRAM={max_memory}k -Djava.security.manager -Dfile.encoding=UTF-8 -Djava.security.policy==/etc/java_policy -Djava.awt.headless=true Main |
Python 2.7 | /usr/bin/python2.7 -m py_compile {src_path} /usr/bin/python2.7 {exe_path} |
Python 3.10 | /usr/bin/python3.10 -m py_compile {src_path} /usr/bin/python3.10 {exe_path} |
PHP 8.1 | /usr/bin/php {exe_path} |
Node.js 16 | /usr/bin/node --stack-size=65536 {exe_path} |
Go | /usr/bin/go build -o {exe_path} {src_path} |
C# | /usr/bin/mcs -optimize+ -out:{exe_path} {src_path} |
Ruby | /usr/bin/ruby {exe_path} |
Rust | /usr/bin/rustc -O -o {exe_path} {src_path} |
Haskell | /usr/bin/ghc -O -outputdir /tmp -o {exe_path} {src_path} |
Free Pascal | /usr/bin/fpc -O2 -o{exe_path} {src_path} |
Plaintext | /bin/cat {exe_path} |
Free Basic | /usr/local/bin/fbc {src_path} |
Assembly (32bit) | /usr/bin/nasm -f elf32 -o {exe_path}.o {src_path} && /usr/bin/gcc -m32 -o {exe_path} {exe_path}.o |
Assembly (64bit) | /usr/bin/nasm -f elf64 -o {exe_path}.o {src_path} && /usr/bin/gcc -o {exe_path} {exe_path}.o |
SystemVerilog 2012 | /usr/bin/iverilog -g2012 -o {exe_path} {src_path} /usr/bin/vvp {exe_path} |
Starting from NOJ v0.18.0
and NOJ JudgeServer v0.3.0
, NOJ JudgeServer provides a SPJ library called testlib, it contains some useful constants and definitions and it would be bundled as a optional SPJ library of C++
.
Right now testlib would be the only SPJ library available but we are planning to support more SPJ libraries in the future.
NOJ JudgeServer provides SPJ support for C
language only prior to v0.3.0
.
Starting from NOJ v0.18.0
and NOJ JudgeServer v0.3.0
, NOJ JudgeServer provides additional support for C++
and PHP
.
Language | Compiler | Additional SPJ Libraries |
---|---|---|
C | gcc (C99) | - |
C++ | g++ (C++11) | testlib |
PHP | php (7.3-cli) | - |
Older versions of NOJ JudgeServer SPJs are feeded with testcase input and user output only. While in latest version of v0.3.0
, It becomes testcase input, testcase output and user output. The changes not only grants testcase output access to SPJs, but also alters the given order. Thus all legacy version of SPJ need to:
- Alter accepted
argc
to 4 and accepts testcase input as first, testcase output as second and user output as third; - Re-bundle testcases archive file to include .out files, then use NOJ v0.18.0 Admin Portal to re-upload the testcases, the
.out
files, if not needed, can be blank or simply the same as input.
Here lists all valid exit code for SPJ:
Verdict | Exit Codes |
---|---|
Accepted | 0 |
Wrong Answer | 1, 2, 4, 8 |
System Error | 3, 7, 255 |
All unlisted exit codes would be viewed as System Error.
Since Linux only accepts last 8 bits of exit code, you can practically use
-1
for System Error for it actually converts to255
. You can also use-255
(1
) for Wrong Answer or-253
(3
) for System Error, etc.
For C++ with testlib support, you can use testlib quitf
function and macro defined _wa
, _ok
and so on without any conversion except Points
and Partically Accepted
status. NOJ Judge Server would recognize them properly and auto-convert them to NOJ JudgeServer standard.
NOJ Verdict | Testlib Verdict |
---|---|
Accepted | _ok |
Wrong Answer | _wa , _pe , _dirt , _unexpected_eof |
System Error | _fail , _points , _partically , _pc |
For Points
and Partically Accepted
status, NOJ would verdict them all System Error no matter what score this SPJ actually nailed. For NOJ does not support single testcase with divided score.
We may support single-testcase-wide partically accepted status in the future.
Here is a simple SPJ checker written in Clang
, this checker checks if the integer user outputs equals the given testcase:
#include <stdio.h>
#define AC 0
#define WA 1
#define ERROR -1
int spj(FILE *input, FILE *output, FILE *user_output);
void close_file(FILE *f){
if(f != NULL){
fclose(f);
}
}
int main(int argc, char *args[]){
FILE *input = NULL, *output = NULL, *user_output = NULL;
int result;
if(argc != 4){
printf("Usage: spj x.in x.out x.ans\n");
return ERROR;
}
input = fopen(args[1], "r");
output = fopen(args[2], "r");
user_output = fopen(args[3], "r");
if(input == NULL || output == NULL || user_output == NULL){
printf("Failed to open output file\n");
close_file(input);
close_file(output);
close_file(user_output);
return ERROR;
}
result = spj(input, output, user_output);
printf("result: %d\n", result);
close_file(input);
close_file(output);
close_file(user_output);
return result;
}
int spj(FILE *input, FILE *output, FILE *user_output){
int a, b;
fscanf(output, "%d", &b);
if(~fscanf(user_output, "%d", &a)) {
if(a == b){
return AC;
}
}
return WA;
}
Here is a simple SPJ checker written in C++
with testlib support, this checker checks if the integer user outputs equals the given testcase:
#include <testlib>
int main(int argc, char * argv[]) {
setName("compares two signed integers");
registerTestlibCmd(argc, argv);
int ja = ans.readInt();
int pa = ouf.readInt();
if (ja != pa) quitf(_wa, "expected %d, found %d", ja, pa);
quitf(_ok, "answer is %d", ja);
}
NOJ JudgeServer Provides exclusive php
language SPJ supports for contest arrangers to be benefited from this dynamic, weakly typed and artistic language, this checker checks if the integer user outputs equals the given testcase:
<?php
class Judge
{
private const ACCEPTED = 0;
private const WRONG_ANSWER = 1;
private const SYSTEM_ERROR = -1;
private $input = false;
private $output = false;
private $user_output = false;
private $verdict = null;
private function settleVerdict(int $ret = 0): void
{
if ($this->input !== false) {
fclose($this->input);
}
if ($this->output !== false) {
fclose($this->output);
}
if ($this->user_output !== false) {
fclose($this->user_output);
}
$this->verdict = $ret;
}
public function __construct($argc, $argv)
{
if ($argc != 4) {
printf("Usage: php {$argv[0]} x.in x.out x.ans\n");
$this->settleVerdict(Judge::SYSTEM_ERROR);
return;
}
$this->input = fopen($argv[1], "r");
$this->output = fopen($argv[2], "r");
$this->user_output = fopen($argv[3], "r");
if ($this->input === false || $this->output === false || $this->user_output === false) {
printf("Failed to open output file\n");
$this->settleVerdict(Judge::SYSTEM_ERROR);
return;
}
}
public static function register($argc, $argv): Judge
{
return new Judge($argc, $argv);
}
private function judge(): int
{
fscanf($this->output, "%d", $b);
if (fscanf($this->user_output, "%d", $a) !== false) {
if ($a == $b) {
return Judge::ACCEPTED;
}
}
return Judge::WRONG_ANSWER;
}
public function getVerdict(): int
{
return $this->verdict ?? $this->judge();
}
}
exit(Judge::register($argc, $argv)->getVerdict());