Linux 下的对拍程序

· · 科技·工程

README

本程序改编大佬 @ICE_Dice1024 的 test_examples.sh,(算是一次更新?)在此感谢在程序编写过程中的 ICE_Dice1024 的帮助。

欢迎大家反映 Bug 或提出 Upd 建议!另外,代码较长,不建议考场手打(除非想震慑旁边选手

Upd Log

ver 1.0:ICE_Dice1024 原版

ver 2.0:

  1. 新增正常对拍,修改了错误信息颜色。
  2. 修改了 differ.log 的储存功能,改为信息追加。
  3. 正常对拍功能中提供了错误数据 copy 功能。

ver 2.1:

  1. 修改 pat.sh 调用参数,区分样例与本地测试。详情见下文。
  2. 整体重编,用函数缩减代码量。
  3. 修改日志文件保存方式。
  4. 支持答案文件 .ans/.out 两种后缀。
  5. 为错误数据 copy 功能单开子目录,方便整理。
  6. 修复本地自测测试点编号问题。

Usage

程序自带报错功能,不必担心记不住。需要注意,本程序命令与 ICE_Dice1024 原版有较多区别(

其中,各项数据均不加 .cpp 后缀。

CODE

#! \bin\bash

_ac="\x1B[92;1mAccepted\x1B[0m"
_wa="\x1B[91;1mWrong Answer\x1B[0m"
_re="\x1B[95;1mRuntime Error\x1B[0m"
_tle="\x1B[94;1mTime Limit Exceed\x1B[0m"
_mle="\x1B[94;1mMemory Limit Exceed\x1B[0m"
_ce="\x1B[93;1mCompile Error\x1B[0m"
_arg_err="\x1B[90;1mArgument Error\x1B[0m"
_file_err="\x1B[90;1mFile Error\x1B[0m"

check() {
    if ! test -e $1.cpp; then
        echo -e "${_file_err}"\
            "Cannot find source file($1.cpp)."
        exit -1
    fi
}

if [ "$1" = "example" ]; then
    if [ $# != 8 ]; then
        echo -e "${_arg_err} Usage \x1B[4m$0"\
            "example <task> <id-range>"\
            "<time-limit> <memory-limit>"\
            "<compile-command>"\
            "<test-type=[0,1]>"\
            "\x1B[0m."
        exit -1
    fi

    exl=$3
    exr=$4
    mod=0
elif [ "$1" = "local" ]; then
    if [ $# != 8 ]; then
        echo -e "${_arg_err} Usage \x1B[4m$0"\
            "local <task> <std> <data>"\
            "<time-limit> <memory-limit>"\
            "<compile-command>"\
            "<test-type=[0,1]>"\
            "\x1B[0m."
        exit -1
    fi

    std=$3
    check $std
    dat=$4
    check $dat
    mod=1
else
    echo -e "${_arg_err}"\
        "Mode should be \"example\" or \"local\"."
    exit -1
fi
cod=$2
check $cod

cmd=$7
typ=$8

if [ $typ != 0 -a $typ != 1 ]; then
    echo -e "${_arg_err}"\
        "The value of test type can only be '0' or '1'."
    exit -1
fi
if [ "$cmd" = "debug" ]; then
    cmd="-fsanitize=undefined,address -Wall"
elif [ "$cmd" = "run" ]; then
    cmd="-O2 -static -std=c++14"
elif [ "$cmd" != "-Ofast" ]; then
    echo -e "${_arg_err}"\
        "Compile command can only be 'debug' or 'run'."
    exit -1
fi

remove() {
    if test $1 $2; then
        rm $2 $3
    fi
}

remove -e compiler.log
remove -e differ.log
remove -e runtime.log
remove -d record -rf

echo "Compiling..."

if ! g++ -o $cod $cod.cpp $cmd 2> compiler.log; then
    echo -e "${_ce} Compilation terminated."
    exit -1
fi
if ! test -s compiler.log; then
    rm compiler.log
fi
if [ $mod = 1 ]; then
    g++ -O2 -o std $std.cpp
    g++ -O2 -o dat $dat.cpp
fi

echo "Testing..."

tim=$(($5*1000))
mem=$(($6*1024))
sta=0

TIMEFORMAT="user %3U"
ulimit -s $mem

getin() {
    clc=$(echo "print(int($(\
        grep 'user' runtime.log | awk '{print $2}'\
        )*1000))" | python3)
    siz=$(grep 'Maximum' runtime.log | awk '{print $6}')
}

deal() {
    if [ $typ = 0 ]; then
        exit 1
    else
        if [ $mod = 1 ]; then
            let j++
            cp data.in record/$1$j.in
            if [ $j = 10 ]; then
                exit 1
            fi
        fi

        sta=1
    fi
}

if [ $mod = 1 ]; then
    mkdir record
fi

trial() {
    tarfile=$1

    ( time /usr/bin/time -v timeout $(($tim/1000+1))\
        ./$cod < data.in > $cod.out ) 2> runtime.log

    val=$?
    if [ $val = 124 ]; then
        echo -e "${_tle} Program timeout on #$i."
        deal TLE
        return 0
    fi
    if [ $val != 0 ]; then
        echo -e "${_re} Program terminated on #$i."
        deal RE
        return 0
    fi

    if ! diff $tarfile $cod.out -Z >> differ.log; then
        echo -e "${_wa} Found different answer on #$i"
        deal WA
        return 0
    fi

    getin
    if [ $clc -gt $tim ]; then
        echo -e "${_tle} Program timeout on #$i."
        deal TLE
        return 0
    fi
    if [ $siz -gt $mem ]; then
        echo -e "${_mle} Program's memory beyond on #$i."
        deal MLE
        return 0
    fi

    echo -e "${_ac} Example #$i passed."\
        "Time: ${clc}ms."\
        "Memory: ${siz}KB."
}

throw() {
    echo -e "${_file_err}"\
        "Cannot find example file($cod$1.$2)."

    if [ $typ = 0 ]; then
        exit -1
    fi
}

if [ $mod = 0 ]; then
    for (( i=exl ; i <= exr ; i++ )) do
        if ! test -e $cod$i.in; then
            throw $i in
            continue
        fi
        if ! test -e $cod$i.out; then
            suf=".ans"
        else
            suf=".out"
        fi
        if ! test -e $cod$i$suf; then
            throw $i ans/out
            continue
        fi

        cp $cod$i.in data.in
        trial $cod$i$suf
    done
else
    for (( i=1 ; ; i++ )) do
        ./dat > data.in
        ./std < data.in > std.out

        trial std.out
    done
fi

exit $sta