新功能:提交诊断和行末文末空白符过滤

ultmaster edited 6 年,3 月前

大家好。

我们增加了两个新功能。

提交诊断

第一个是所有提交现在已经支持对提交详情的查看。除了部分比赛,在错误提交达到一定次数之后,会显示 Need some help? 的提示,你可以选择支付一些 EMB 来获取关于题目 Debug 的帮助。之前是可以下载数据点,我发现大家已经用得非常 6 了。但部分大数据点全部下载下来根本不可能 Debug,而且对于数据点较多的题目全部下载下来要付出较多的 EMB。为了更好地帮助调试,从现在起的所有提交都可以拿到摘要。

包括输入信息、输出信息和比较程序 (checker) 的评价(哪里错了)。

虽然下载数据功能从即日起已经正式关闭,但是不用担心,你之前购买的所有测试点仍然可以在你的账单记录中找到,可以重复下载。

行末文末空白符过滤

我们上线了一个新的默认比较程序 (default checker),将在比较输出和答案是过滤行末文末空格,并大大优化了输入输出效率。

优化的结果是这个 checker 变得非常复杂和易碎。现将其源代码直接在本 OJ 上开放,如果认为此 checker 存在漏洞的,请携带提交程序拨打报警电话。我们将尽快解决。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

#define BUFFER_SIZE 100000
#define WA_EXIT_CODE 1
#define FAIL_EXIT_CODE 3

FILE *ouf, *ans, *ret;

inline bool isLineEnding(char c) {
    return c == '\r' || c == '\n';
}

inline bool isValidChar(char c) {
    return c && !isspace(c);
}

inline bool isCompressChar(char c) {
    return c && !isLineEnding(c);
}

class IO {
private:
    FILE* file;
    char ch, buf[BUFFER_SIZE], *p1, *p2;

public:
    int lineCount;

    explicit IO(FILE* f): file(f), ch(0), p1(buf), p2(buf), lineCount(1) {
        memset(buf, 0, sizeof buf);
    }

    inline int nextchar(char &r) {
        if (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, BUFFER_SIZE, file), p1 == p2)) return 0;
        r = *p1++; if (r == '\n') lineCount++; return 1;
    }

    inline string compress() {
        char *lptr = p1, *rptr = p1;
        string ans; int i;
        for (i = 0; i < 16; ++i) {
            if (--lptr != buf - 1 && isCompressChar(*lptr))
                ans += *lptr;
            else break;
        }
        if (i == 16) ans += "...";
        reverse(ans.begin(), ans.end());

        for (i = 0; i < 15; ++i) {
            if (rptr != p2 && isCompressChar(*rptr))
                ans += *rptr++;
            else break;
        }
        if (i == 15) ans += "...";
        return ans;
    }
};

void quit(int result) {
    fclose(ouf); fclose(ans); fclose(ret);
    exit(result);
}

void registerSpj(int argc, char* argv[]) {
    if (argc < 4 || argc > 6) {
        cout << "Program must be run with the following arguments: "
             << "<input-file> <output-file> <answer-file> [<report-file>]"
             << endl;
        exit(FAIL_EXIT_CODE);
    } else if (argc == 4) {
        ret = stdout;
    } if (argc == 5) {
        ret = fopen(argv[4], "w");
        if (ret == nullptr)
            exit(FAIL_EXIT_CODE);
    }

    ouf = fopen(argv[2], "r");
    if (ouf == nullptr) exit(FAIL_EXIT_CODE);
    ans = fopen(argv[3], "r");
    if (ans == nullptr) exit(FAIL_EXIT_CODE);
}

int main(int argc, char * argv[]) {
    registerSpj(argc, argv);

    IO outio(ouf), ansio(ans);

    char a, b;
    int ans_ok, ouf_ok;

    while (true) {
        ans_ok = ansio.nextchar(a);
        ouf_ok = outio.nextchar(b);

        if (ans_ok && ouf_ok) {
            if (a == b) {
                // not eof and equal (ok)
                continue;
            } else if (a == '\n') {
                // ans is at eol but ouf is not
                do {
                    if (isValidChar(b)) {
                        fprintf(ret, "wrong answer: unexpected character at the end of line %d\n", outio.lineCount);
                        quit(WA_EXIT_CODE);
                    }
                } while (outio.nextchar(b) && b != '\n');
            } else if (b == '\n') {
                // ouf is at eol but ans if not
                do {
                    if (isValidChar(a)) {
                        fprintf(ret, "wrong answer: character missing at the end of line %d\n", outio.lineCount - 1);
                        quit(WA_EXIT_CODE);
                    }
                } while (ansio.nextchar(a) && a != '\n');
            } else {
                // wrong answer
                fprintf(ret, "wrong answer: line %d differ - expected: '%s', found: '%s'\n", outio.lineCount,
                        ansio.compress().c_str(), outio.compress().c_str());
                quit(WA_EXIT_CODE);
            }
        } else {
            if (!ans_ok && !ouf_ok) {
                // both encountered eof
                break;
            } else if (!ans_ok) {
                // ouf is still not eof
                do {
                    if (isValidChar(b)) {
                        fprintf(ret, "wrong answer: unexpected output at eof\n");
                        quit(WA_EXIT_CODE);
                    }
                } while (outio.nextchar(b));
            } else {
                // ans is still not eof but ouf is eof now
                do {
                    if (isValidChar(a)) {
                        fprintf(ret, "wrong answer: output missing at eof\n");
                        quit(WA_EXIT_CODE);
                    }
                } while (ansio.nextchar(a));
            }
        }
    }

    fprintf(ret, "ok\n");
    return 0;
}

最后感谢大家对 EOJ 的支持!

Comments

10175102141

希望把所有的题目的分数做个排序orz

Master X

judge好评!

kblack

借楼提醒大家,发现出现 System Error 或卡在 Waiting 状态要及时报警哦!

10175101148

好像根本买不到靠后的数据点啊....

ultmaster

因为你前面就错了后面的根本就不跑了啊(微笑

10165102128

膜拜大佬

10175101148

不是因为限制了512KB吗?只能看几行的input有什么用呢…为什么不同时保留新旧两种方式?