Skip to content

📃 check.cpp

Nepumi-Jr edited this page May 25, 2024 · 2 revisions

เป็นไฟล์ Script ที่มีมาตั้งแต่สมัยก่อน ที่พี่กฤษฏิ์เขียนไว้ (BLESSED) โดยข้อมูลที่ check.cpp จะรู้คือ

  1. ที่อยู่ของไฟล์ .sol ของเคสแต่ละเคส
  2. ที่อยู่ของไฟล์ .in ของเคสแต่ละเคสเช่นกัน
  3. ที่อยู่ของไฟล์โค้ดของที่ส่ง
  • นอกจากนี้ ตัวตรวจสามารถรับ Output ของผู้ส่งได้จากการอ่านไฟล์ output.txt ได้เลย
  • ผลการตรวจสามารถบอกได้จากการเขียนไฟล์ grader_result.txt ว่าผ่านหรือไม่ผ่าน
  • โดยผ่านจะใช้สัญลักษณ์ P และไม่ผ่านจะใช้สัญลักษณ์ ขีด หรือ W

ตัวอย่างโจทย์

แมวของคุณชอบเลข 69 หรือต่ำกว่า หากเกินนั้น แมวของคุณจะไม่สนใจทันที

งานของคุณคือ ให้เขียนโปรแกรมแสดงตัวเลข 69 หรือต่ำกว่า บนหน้าจอ

Input

(ไม่มี)

Output

จำนวนเต็ม หนึ่งจำนวนที่น้อยกว่าหรือเท่ากับ 69

ตัวอย่าง check.cpp ของข้อนี้

#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
#include <algorithm>
using namespace std;

std::ofstream result("grader_result.txt"); // ตัวเปิดไฟล์ "grader_result.txt"
void correct() {
	::result << 'P'; // เขียนไฟล์นั้นว่า "P"
	::exit(0);
}
void wrong() {
	::result << 'W'; // เขียนไฟล์นั้นว่า "W"
	::exit(0);
}
int main(int argc, char* argv[]) {
	std::ifstream sol(argv[1]); 	//อ่าน .sol ไฟล์จาก argv ข้อที่ 1
	std::ifstream inp(argv[2]); 	//อ่าน .in ไฟล์จาก argv ข้อที่ 2
	std::ifstream cod(argv[3]); 	//อ่าน code จากไฟล์ที่น้องส่ง จาก argv ข้อที่ 3
	std::ifstream out("output.txt");//อ่าน output ที่น้อง Output ออกมา

    int num;
    out >> num;
    if (num <= 69) correct();
    else wrong();
}

สคริปของพี่กฤษฏิ์

#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
#include <algorithm>


using namespace std;

std::ofstream result("grader_result.txt");
void correct() {
	::result << 'P';
	::exit(0);
}
void wrong() {
	::result << 'W';
	::exit(0);
}
int main(int argc, char* argv[]) {
	std::ifstream sol(argv[1]); 	//OPEN SOLUTION FILE
	std::ifstream inp(argv[2]); 	//OPEN INPUT    FILE
	std::ifstream cod(argv[3]); 	//OPEN SOURCE   FILE
	std::ifstream out("output.txt");//OPEN USER'S OUTPUT FILE

#ifdef __NOT_ALLOW_CPP__
	if (char c = std::string(argv[3]).back()
		; c == 'p' || c == 'P') ::wrong();
#endif
#ifdef __SOURCE_LIMMIT__
	cod.seekg(0, std::ios_base::end);
	if (cod.tellg() > __SOURCE_LIMMIT__) ::wrong();
	cod.clear();
	cod.seekg(0, std::ios_base::beg);
#endif
#ifdef __RESERVE_WORD__
	std::string code, tmp;
	while (cod >> tmp) code += tmp;
	code.erase(std::remove(code.begin(), code.end(), '\\'), code.end());
	for (auto [str, cnt] : std::map<std::string, int>__RESERVE_WORD__) {
		for (auto it = code.begin(); it != code.end(); ++it) {
			if (std::equal(str.begin(), str.end(), it) and !cnt--) {
				::wrong();
			}
		}
	}
#endif
	bool good_sol = true;
	bool good_out = true;
	std::string str_sol, str_out;
	std::ios_base::sync_with_stdio(0);
	do {
		good_sol = bool(sol >> str_sol);
		good_out = bool(out >> str_out);
	} while (good_sol and good_out and str_sol == str_out);
	if (!good_sol and !good_out) correct(); // read to end
	else wrong();
}

สคริปของพี่กฤษฏิ์ (ข้อ 566 is_substr_semicolon)

#include <bits/stdc++.h>
#define __SOURCE_LIMMIT__ 1000000000
#define __RESERVE_WORD__  {{"goto", 0}, {"while", 1}, {"define", 0}, {"if", 0}, {"#include", 1}, {"stdio.h", 1}, {"string.h", 0}, {"stdlib.h", 0}, {";", 3}}
#define __NOT_ALLOW_CPP__
using namespace std;

std::ofstream result("grader_result.txt");
void correct(){
    ::result << 'P';
    ::exit(0);
}
void wrong(){
    ::result << 'W';
    ::exit(0);
}
int main(int argc, char * argv[]){
    std::ifstream sol(argv[1]);     //OPEN SOLUTION FILE
    std::ifstream inp(argv[2]);     //OPEN INPUT    FILE
    std::ifstream cod(argv[3]);     //OPEN SOURCE   FILE
    std::ifstream out("output.txt");//OPEN USER'S OUTPUT FILE

#ifdef __NOT_ALLOW_CPP__
    if (char c = std::string(argv[3]).back()
        ; c == 'p' || c == 'P') ::wrong();
#endif
#ifdef __SOURCE_LIMMIT__
    cod.seekg(0, std::ios_base::end);
    if (cod.tellg() > __SOURCE_LIMMIT__) ::wrong();
    cod.clear();
    cod.seekg(0, std::ios_base::beg);
#endif
#ifdef __RESERVE_WORD__
    std::string code, tmp;
    while (cod >> tmp) code += tmp;
    code.erase (std::remove(code.begin(), code.end(), '\\'), code.end());
    for (auto [str, cnt] :     std::map<std::string, int>__RESERVE_WORD__){
        for (auto it = code.begin(); it != code.end(); ++it){
            if (std::equal(str.begin(), str.end(), it) and !cnt--){
                ::wrong();
    }}}
#endif
    bool good_sol = true;
    bool good_out = true;
    std::string str_sol, str_out;
    std::ios_base::sync_with_stdio(0);
    do{
        good_sol = bool(sol >> str_sol);
        good_out = bool(out >> str_out);
    }while (good_sol and good_out and str_sol == str_out);
    if (!good_sol and !good_out) correct(); // read to end
    else wrong();
}

ซึ่งอาจดูเยอะ ดูยาว แต่สคริปนี้มีประโยชน์อยู่มากๆๆๆๆๆๆ

#include <algorithm>

//#define __NOT_ALLOW_CPP__
//#define __SOURCE_LIMMIT__ 2000
//#define __RESERVE_WORD__ "for", "while", "loop"

using namespace std;

ซึ่งในส่วนของ

#define __RESERVE_WORD__ 

สามารถทำได้โดยการใส่เป็น std::map<string, int> โดย key ของ map คือการกำหนดคำต้องห้ามในโปรแกรม และ int จะเป็นจำนวนครั้งที่สามารถพบได้ในโปรแกรม เช่น ในสคริปของพี่กฤษฏิ์ (ข้อ 566 is_substr_semicolon) {"goto", 0} หมายถึง ห้ามมีคำว่า goto อยู่ในโปรแกรม และ {";", 3} หมายถึง สามารถมีคำว่า ; ได้ 3 ครั้ง เป็นต้น

ทั้ง 3 การ #define เป็นการเพิ่มเงื่อนไขโจทย์เพื่อให้ยากขึ้น โดย...

  • #define __NOT_ALLOW_CPP__ คือการห้ามส่งภาษา c++
  • #define __SOURCE_LIMMIT__ คือการกำหนดขนาดไฟล์ที่ส่ง (มีหน่วยเป็น byte)
  • #define __RESERVE_WORD__ คือการกำหนดคำต้องห้ามในโปรแกรม หากมีคำเหล่านั้นอยู่ จะทำให้ได้ - (ขีด)

📁 ตัวอย่างโครงสร้างของไฟล์โจทย์

706 อะไรก็ได้ อย่าเรียงก็พอ
 |- 1.in
 |- 1.sol
 |- 2.in
 |- 2.sol
 |- 3.in
 |- ...
 |- 10.sol
 |- check.cpp
 .