Skip to content

Commit 56f8a5c

Browse files
committed
add checker
1 parent e967595 commit 56f8a5c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+675
-3
lines changed

checker/default.nix

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{ pkgs ? import <nixpkgs> {} }: with pkgs;
2+
stdenv.mkDerivation rec {
3+
pname = "luogu-checkers";
4+
version = "0.1.0";
5+
6+
src = ./src;
7+
8+
buildInputs = [ cmake ];
9+
10+
configurePhase = "cmake .";
11+
12+
buildPhase = "make";
13+
14+
installPhase = ''
15+
mkdir -p $out/bin
16+
mv {noip,strict}-checker $out/bin
17+
'';
18+
}

checker/src/.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CMakeCache.txt
2+
CMakeFiles
3+
CMakeScripts
4+
Testing
5+
Makefile
6+
cmake_install.cmake
7+
install_manifest.txt
8+
compile_commands.json
9+
CTestTestfile.cmake
10+
noip-checker
11+
strict-checker

checker/src/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
cmake_minimum_required(VERSION 3.1)
2+
project(checker)
3+
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
4+
set(CMAKE_BUILD_TYPE Release)
5+
set(CMAKE_CXX_STANDARD 14)
6+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
7+
add_executable(noip-checker noip-checker.cpp)
8+
install(TARGETS noip-checker DESTINATION /usr/bin)
9+
add_executable(strict-checker strict-checker.cpp)
10+
install(TARGETS strict-checker DESTINATION /usr/bin)

checker/src/file.h

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#include <fstream>
2+
3+
//#define DEBUG
4+
#ifdef DEBUG
5+
#define DEBUG_OUTPUT(x) \
6+
do { \
7+
std::cout << x << std::endl; \
8+
} while (0)
9+
#else
10+
#define DEBUG_OUTPUT(x)
11+
#endif
12+
13+
class File {
14+
public:
15+
File(std::ifstream &&stream) : mFile(std::move(stream)) {}
16+
17+
// Move the cursor 1 byte forward. It will automatially read the file
18+
// into the buffer when needed.
19+
// Return true when succeed; return false if the EOF has been reached.
20+
bool next() noexcept {
21+
if (mBufferPosition < mValidBufferSize - 1)
22+
mBufferPosition++;
23+
else {
24+
if (mFile.eof()) return false;
25+
mFile.clear();
26+
mFile.read(mBuffer, BufferSize);
27+
mValidBufferSize = mFile.gcount();
28+
DEBUG_OUTPUT("Reading files to buffer, new valid buffer size: "<< mValidBufferSize);
29+
if (mValidBufferSize == 0)
30+
return false;
31+
mBufferPosition = 0;
32+
}
33+
if (get() == '\n') { mLine++; mColumn=0; }
34+
else mColumn++;
35+
return true;
36+
}
37+
38+
// Will the next next() return false?
39+
bool willEOF() noexcept {
40+
return mBufferPosition >= mValidBufferSize - 1 && (mFile.eof() || mFile.peek() == EOF);
41+
}
42+
43+
// Read the remaining file and return if there is any \n.
44+
bool newLineInRemainingFile(bool includingNow) noexcept {
45+
if (get() == '\n' && includingNow) return true;
46+
while (next()) {
47+
DEBUG_OUTPUT("In newLineInRemainingFile:while, get()="<<get()<<":"<<int(get()));
48+
if (get() == '\n') return true;
49+
}
50+
return false;
51+
}
52+
53+
// Read the remaining file and return if there is any non-space character.
54+
// Note that this function will consume the remaining file.
55+
bool charactersInRemainingFile(bool includingNow) noexcept {
56+
if(includingNow && get() != ' ' && get() != '\r' && get() != '\0' && get() != '\n')
57+
return true;
58+
while (next()) {
59+
DEBUG_OUTPUT("In charactersInRemainingFile, get()="<<get()<<":"<<int(get()));
60+
if (get() != ' ' && get() != '\r' && get() != '\0' && get() != '\n')
61+
return true;
62+
}
63+
return false;
64+
}
65+
66+
// Read the remaining file and return if there is any non-space character.
67+
// Note that this function will consume the remaining line.
68+
bool charactersInRemainingLine(bool includingNow) noexcept {
69+
if(willEOF()) return includingNow?(get()!=' '&&get()!='\r'&&get()!='\n'&&get()!='\0'):false;
70+
if(!includingNow) if (!next()) return false;
71+
while (get() != '\n') {
72+
DEBUG_OUTPUT("In charactersInRemainingLine, get()="<<get()<<":"<<int(get()));
73+
if (get()!=' '&&get()!='\r'&&get()!='\0') return true;
74+
if (!next()) break;
75+
}
76+
return false;
77+
}
78+
79+
char get() const noexcept { return mBuffer[mBufferPosition]; }
80+
unsigned long long getLine() const noexcept { return mLine; }
81+
unsigned long long getColumn() const noexcept { return mColumn; }
82+
std::streamsize getBufferPosition() const noexcept { return mBufferPosition; }
83+
84+
void _dbg() const noexcept {
85+
DEBUG_OUTPUT("line " << mLine << ", column " << mColumn
86+
<< ", bufferpos " << mBufferPosition
87+
<< "/" << mValidBufferSize
88+
<< " eof?:" << mFile.eof()
89+
<< " char:" << (get()=='\n'?'*':get())
90+
<< ":" << int(get()));
91+
}
92+
93+
private:
94+
static constexpr size_t BufferSize = 1024 * 1024; // 1MB
95+
unsigned long long mLine = 1;
96+
unsigned long long mColumn = 0;
97+
std::streamsize mBufferPosition = 0;
98+
std::streamsize mValidBufferSize = 0;
99+
std::ifstream mFile;
100+
char mBuffer[BufferSize];
101+
};

checker/src/noip-checker.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#include <iostream>
2+
#include "file.h"
3+
4+
// Compare two files using NOIP rules.
5+
// i.e. ignore spaces before \n or \n before EOF
6+
//
7+
// Return value:
8+
// return true if the output passes the case;
9+
// otherwise the function will output the error to stdout and returns false
10+
bool compare(std::ifstream &&outputStream, std::ifstream &&answerStream) {
11+
File output(std::move(outputStream)), answer(std::move(answerStream));
12+
for (;;) {
13+
// Handle EOF
14+
if (!output.next()) {
15+
DEBUG_OUTPUT("!output.next()");
16+
17+
if(answer.willEOF()) return true;
18+
19+
if (answer.charactersInRemainingLine(false) && output.getLine()==answer.getLine()){
20+
std::cerr << "wrong answer Too short on line " << answer.getLine() << ".";
21+
return false;
22+
} else if (answer.charactersInRemainingFile(true)){
23+
std::cerr << "wrong answer Too few lines."; // actually too few
24+
return false;
25+
} else return true;
26+
}
27+
28+
if (!answer.next()) {
29+
DEBUG_OUTPUT("!answer.next()");
30+
if (output.charactersInRemainingLine(true) && output.getLine()==answer.getLine()){
31+
std::cerr << "wrong answer Too long on line " << answer.getLine() << ".";
32+
return false;
33+
} else if (output.charactersInRemainingFile(true)){
34+
std::cerr << "wrong answer Too many lines."; // actually too many
35+
return false;
36+
} else return true;
37+
}
38+
39+
output._dbg();answer._dbg();
40+
// Compare
41+
if (output.get() != answer.get()) {
42+
DEBUG_OUTPUT("output.get() != answer.get()");
43+
auto line = answer.getLine();
44+
auto column = answer.getColumn();
45+
auto charRead = output.get();
46+
auto expected = answer.get();
47+
bool outputHasMore = output.charactersInRemainingLine(true);
48+
bool answerHasMore = answer.charactersInRemainingLine(true);
49+
DEBUG_OUTPUT("outputHasMore=" << outputHasMore << ",answerHasMore=" << answerHasMore);
50+
if (outputHasMore || answerHasMore) {
51+
if (outputHasMore && answerHasMore) {
52+
std::cerr << "wrong answer On line " << line << " column " << column << ", read ";
53+
if (charRead <= 32 || charRead >= 127)
54+
std::cerr << "(ASCII " << static_cast<int>(charRead) << ")";
55+
else
56+
std::cerr << charRead;
57+
std::cerr << ", expected " << expected << ".";
58+
} else
59+
std::cerr << "wrong answer Too " << (answerHasMore ? "short" : "long") << " on line " << line << ".";
60+
return false;
61+
}
62+
}
63+
}
64+
return true;
65+
}
66+
67+
int main(int argc, char *argv[]) {
68+
if (argc < 4) {
69+
std::cerr << "FAIL Program must be run with the following arguments: <input-file> <output-file> <answer-file>" << std::endl;
70+
return -1;
71+
}
72+
73+
// the input file (argv[1]) is ignored since it's not needed.
74+
auto outputFile = std::ifstream(argv[2], std::ifstream::binary);
75+
if (outputFile.fail()) {
76+
std::cerr << "FAIL Output file not found: \"" << argv[2] << "\"" << std::endl;
77+
return -1;
78+
}
79+
auto answerFile = std::ifstream(argv[3], std::ifstream::binary);
80+
if (answerFile.fail()) {
81+
std::cerr << "FAIL Answer file not found: \"" << argv[3] << "\"" << std::endl;
82+
return -1;
83+
}
84+
if (compare(std::move(outputFile), std::move(answerFile)))
85+
std::cerr << "ok accepted";
86+
// otherwise the error is already outputed in compare
87+
}

checker/src/strict-checker.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#include <iostream>
2+
#include "file.h"
3+
4+
// Compare two files using NOIP rules.
5+
// i.e. ignore spaces before \n or \n before EOF
6+
//
7+
// Return value:
8+
// return true if the output passes the case;
9+
// otherwise the function will output the error to stdout and returns false
10+
bool compare(std::ifstream &&outputStream, std::ifstream &&answerStream) {
11+
File output(std::move(outputStream)), answer(std::move(answerStream));
12+
for (;;) {
13+
// Handle EOF
14+
if (!output.next()) {
15+
DEBUG_OUTPUT("!output.next()");
16+
17+
if (answer.willEOF()
18+
&& answer.getLine()==output.getLine()
19+
&& answer.getColumn() == output.getColumn()
20+
&& answer.getBufferPosition() == output.getBufferPosition())
21+
return true;
22+
23+
if (answer.charactersInRemainingLine(false) && output.getLine()==answer.getLine())
24+
std::cerr << "wrong answer Too short on line " << answer.getLine() << ".";
25+
else if (answer.charactersInRemainingFile(true))
26+
std::cerr << "wrong answer Too few lines."; // actually too few
27+
else std::cerr << "wrong output format Wrong format";
28+
return false;
29+
}
30+
31+
if (!answer.next()) {
32+
DEBUG_OUTPUT("!answer.next()");
33+
if (output.charactersInRemainingLine(true) && output.getLine()==answer.getLine())
34+
std::cerr << "wrong answer Too long on line " << answer.getLine() << ".";
35+
else if (output.charactersInRemainingFile(true))
36+
std::cerr << "wrong answer Too many lines."; // actually too many
37+
else std::cerr << "wrong output format Wrong format";
38+
return false;
39+
}
40+
41+
output._dbg();answer._dbg();
42+
// Compare
43+
if (output.get() != answer.get()) {
44+
DEBUG_OUTPUT("output.get() != answer.get()");
45+
auto line = answer.getLine();
46+
auto column = answer.getColumn();
47+
auto charRead = output.get();
48+
auto expected = answer.get();
49+
bool outputHasMore = output.charactersInRemainingLine(true);
50+
bool answerHasMore = answer.charactersInRemainingLine(true);
51+
DEBUG_OUTPUT("outputHasMore=" << outputHasMore << ",answerHasMore=" << answerHasMore);
52+
if (outputHasMore || answerHasMore) {
53+
if (outputHasMore && answerHasMore) {
54+
std::cerr << "wrong answer On line " << line << " column " << column << ", read ";
55+
if (charRead <= 32 || charRead >= 127)
56+
std::cerr << "(ASCII " << static_cast<int>(charRead) << ")";
57+
else
58+
std::cerr << charRead;
59+
std::cerr << ", expected " << expected << ".";
60+
} else
61+
std::cerr << "Too " << (answerHasMore ? "short" : "long") << " on line " << line << ".";
62+
return false;
63+
}
64+
}
65+
}
66+
return true;
67+
}
68+
69+
int main(int argc, char *argv[]) {
70+
if (argc < 4) {
71+
std::cerr << "FAIL Program must be run with the following arguments: <input-file> <output-file> <answer-file>" << std::endl;
72+
return -1;
73+
}
74+
75+
// the input file (argv[1]) is ignored since it's not needed.
76+
auto outputFile = std::ifstream(argv[2], std::ifstream::binary);
77+
if (outputFile.fail()) {
78+
std::cerr << "wrong output format Output file not found: \"" << argv[2] << "\"" << std::endl;
79+
return -1;
80+
}
81+
auto answerFile = std::ifstream(argv[3], std::ifstream::binary);
82+
if (answerFile.fail()) {
83+
std::cerr << "FAIL Answer file not found: \"" << argv[3] << "\"" << std::endl;
84+
return -1;
85+
}
86+
if (compare(std::move(outputFile), std::move(answerFile)))
87+
std::cerr << "ok accepted";
88+
// otherwise the error is already outputed in compare
89+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
123
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
233
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
a
2+
.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
a
2+
1

0 commit comments

Comments
 (0)