update polygon package parsing & testing
This commit is contained in:
579
POLYGON_PACKAGE_STRUCTURE.md
Normal file
579
POLYGON_PACKAGE_STRUCTURE.md
Normal file
@@ -0,0 +1,579 @@
|
||||
# Структура пакета Polygon
|
||||
|
||||
## 📦 Типичная структура Polygon пакета
|
||||
|
||||
```
|
||||
problem-name.zip
|
||||
│
|
||||
├── problem.xml ← Главный дескриптор задачи
|
||||
│
|
||||
├── tests/ ← Тесты для проверки решений
|
||||
│ ├── 01 ← Входные данные (без расширения!)
|
||||
│ ├── 01.a ← Ответы (могут отсутствовать)
|
||||
│ ├── 02
|
||||
│ ├── 02.a
|
||||
│ └── ...
|
||||
│
|
||||
├── files/ ← Вспомогательные файлы
|
||||
│ ├── testlib.h ← Библиотека для checker/validator/generator
|
||||
│ ├── olymp.sty ← LaTeX стиль для statements
|
||||
│ ├── problem.tex ← Шаблон условия
|
||||
│ ├── statements.ftl ← FreeMarker шаблон
|
||||
│ │
|
||||
│ ├── tests/ ← Тесты для checker/validator
|
||||
│ │ ├── checker-tests/
|
||||
│ │ │ ├── 01
|
||||
│ │ │ ├── 01.a
|
||||
│ │ │ └── 01.o ← Ожидаемый output
|
||||
│ │ │
|
||||
│ │ └── validator-tests/
|
||||
│ │ ├── 01
|
||||
│ │ ├── 02
|
||||
│ │ └── ...
|
||||
│ │
|
||||
│ ├── g.cpp ← Generator (генератор тестов)
|
||||
│ ├── g.exe
|
||||
│ ├── v.cpp ← Validator (валидатор входных данных)
|
||||
│ ├── v.exe
|
||||
│ ├── check.cpp ← Checker (проверка ответа)
|
||||
│ ├── check.exe
|
||||
│ ├── interactor.cpp ← Interactor (для интерактивных задач)
|
||||
│ ├── interactor.exe
|
||||
│ │
|
||||
│ └── [resource files] ← Дополнительные ресурсы для решений
|
||||
│ ├── aplusb.h ← Header для grader-задач
|
||||
│ ├── grader.cpp ← Grader для компиляции с решением
|
||||
│ └── main.py ← Python wrapper для grader
|
||||
│
|
||||
├── solutions/ ← Эталонные решения
|
||||
│ ├── sol.cpp ← Главное (main) решение
|
||||
│ ├── sol.exe
|
||||
│ ├── sol.py
|
||||
│ ├── sol.java
|
||||
│ │
|
||||
│ ├── sol-accepted-1.cpp ← Дополнительные AC решения
|
||||
│ ├── sol-wa.cpp ← Wrong Answer решения (для теста)
|
||||
│ ├── sol-tl.cpp ← Time Limit решения
|
||||
│ ├── sol-ml.cpp ← Memory Limit решения
|
||||
│ └── ...
|
||||
│
|
||||
├── statements/ ← Условия задачи
|
||||
│ ├── english/
|
||||
│ │ ├── problem.tex ← Исходник условия (LaTeX)
|
||||
│ │ ├── problem-properties.json
|
||||
│ │ ├── tutorial.tex ← Разбор задачи
|
||||
│ │ ├── example.01 ← Примеры из условия (input)
|
||||
│ │ └── example.01.a ← Примеры из условия (output)
|
||||
│ │
|
||||
│ ├── russian/
|
||||
│ │ └── ...
|
||||
│ │
|
||||
│ ├── .html/ ← Сгенерированные HTML
|
||||
│ │ ├── english/
|
||||
│ │ │ ├── problem.html
|
||||
│ │ │ ├── tutorial.html
|
||||
│ │ │ └── problem-statement.css
|
||||
│ │ └── russian/
|
||||
│ │
|
||||
│ └── .pdf/ ← Сгенерированные PDF
|
||||
│ ├── english/
|
||||
│ │ ├── problem.pdf
|
||||
│ │ └── tutorial.pdf
|
||||
│ └── russian/
|
||||
│
|
||||
├── statement-sections/ ← Секции условия (модульно)
|
||||
│ ├── english/
|
||||
│ │ ├── legend.tex
|
||||
│ │ ├── input.tex
|
||||
│ │ ├── output.tex
|
||||
│ │ ├── notes.tex
|
||||
│ │ ├── scoring.tex
|
||||
│ │ └── examples/
|
||||
│ └── russian/
|
||||
│
|
||||
├── materials/ ← Материалы для участников
|
||||
│ ├── grader-cpp.zip ← Grader для C++
|
||||
│ ├── grader-py.zip ← Grader для Python
|
||||
│ └── ...
|
||||
│
|
||||
├── scripts/ ← Скрипты для работы с пакетом
|
||||
│ ├── gen-answer.sh
|
||||
│ ├── gen-input-via-files.sh
|
||||
│ ├── run-validator-tests.sh
|
||||
│ └── ...
|
||||
│
|
||||
├── check.cpp ← Checker в корне (копия)
|
||||
├── check.exe
|
||||
├── doall.sh ← Скрипт сборки всего
|
||||
├── doall.bat
|
||||
├── wipe.sh ← Скрипт очистки
|
||||
├── wipe.bat
|
||||
└── tags ← Теги задачи (metadata)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📄 Основные файлы и их назначение
|
||||
|
||||
### 1. **problem.xml** (обязательный)
|
||||
|
||||
Центральный дескриптор задачи:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<problem revision="17" short-name="example-problem" url="...">
|
||||
<names>
|
||||
<name language="english" value="Problem Title"/>
|
||||
</names>
|
||||
|
||||
<judging>
|
||||
<testset name="tests">
|
||||
<time-limit>2000</time-limit> <!-- мс -->
|
||||
<memory-limit>268435456</memory-limit> <!-- байты = 256 MB -->
|
||||
<test-count>51</test-count>
|
||||
<input-path-pattern>tests/%02d</input-path-pattern>
|
||||
<answer-path-pattern>tests/%02d.a</answer-path-pattern>
|
||||
|
||||
<tests>
|
||||
<test method="manual" sample="true"/> <!-- ручной, в примерах -->
|
||||
<test cmd="gen 100" method="generated"/> <!-- сгенерированный -->
|
||||
<test cmd="gen 1000" method="generated"/>
|
||||
...
|
||||
</tests>
|
||||
</testset>
|
||||
</judging>
|
||||
|
||||
<assets>
|
||||
<checker name="std::ncmp.cpp" type="testlib">
|
||||
<source path="files/check.cpp" type="cpp.g++17"/>
|
||||
<binary path="check.exe" type="exe.win32"/>
|
||||
</checker>
|
||||
|
||||
<validators>
|
||||
<validator>
|
||||
<source path="files/v.cpp" type="cpp.g++17"/>
|
||||
<binary path="files/v.exe" type="exe.win32"/>
|
||||
</validator>
|
||||
</validators>
|
||||
|
||||
<solutions>
|
||||
<solution tag="main">
|
||||
<source path="solutions/sol.cpp" type="cpp.g++17"/>
|
||||
<binary path="solutions/sol.exe" type="exe.win32"/>
|
||||
</solution>
|
||||
<solution tag="accepted">
|
||||
<source path="solutions/sol.py" type="python.3"/>
|
||||
</solution>
|
||||
<solution tag="wrong-answer">
|
||||
<source path="solutions/sol-wa.cpp" type="cpp.g++17"/>
|
||||
</solution>
|
||||
</solutions>
|
||||
</assets>
|
||||
</problem>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. **testlib.h** (стандартная библиотека)
|
||||
|
||||
Библиотека от MikeMirzayanov для написания:
|
||||
- **Checkers** - проверка правильности ответа
|
||||
- **Validators** - проверка корректности входных данных
|
||||
- **Generators** - генерация тестов
|
||||
- **Interactors** - интерактивное взаимодействие
|
||||
|
||||
**Основные функции:**
|
||||
|
||||
```cpp
|
||||
#include "testlib.h"
|
||||
|
||||
// Checker
|
||||
int main(int argc, char* argv[]) {
|
||||
registerTestlibCmd(argc, argv);
|
||||
|
||||
int jans = ans.readInt(); // Правильный ответ
|
||||
int pans = ouf.readInt(); // Ответ участника
|
||||
|
||||
if (jans == pans)
|
||||
quitf(_ok, "Correct");
|
||||
else
|
||||
quitf(_wa, "Wrong answer: %d instead of %d", pans, jans);
|
||||
}
|
||||
|
||||
// Validator
|
||||
int main(int argc, char* argv[]) {
|
||||
registerValidation(argc, argv);
|
||||
|
||||
int n = inf.readInt(1, 100000, "n");
|
||||
inf.readEoln();
|
||||
inf.readEof();
|
||||
}
|
||||
|
||||
// Generator
|
||||
int main(int argc, char* argv[]) {
|
||||
registerGen(argc, argv, 1);
|
||||
|
||||
int n = opt<int>("n");
|
||||
println(n);
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
println(rnd.next(1, 1000000));
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. **Тесты (tests/)**
|
||||
|
||||
**Формат:**
|
||||
```
|
||||
tests/01 ← Входные данные (plain text, без расширения)
|
||||
tests/01.a ← Ответ (answer file)
|
||||
```
|
||||
|
||||
**Пример:**
|
||||
```
|
||||
# tests/01 (input)
|
||||
2 3
|
||||
|
||||
# tests/01.a (answer)
|
||||
5
|
||||
```
|
||||
|
||||
**Метаданные из problem.xml:**
|
||||
```xml
|
||||
<tests>
|
||||
<test method="manual" sample="true"/> <!-- tests/01 - вручную, в примерах -->
|
||||
<test cmd="gen 10 5" method="generated"/> <!-- tests/02 - сгенерирован -->
|
||||
<test cmd="gen 100 50" method="generated"/> <!-- tests/03 -->
|
||||
</tests>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. **Generator (g.cpp)**
|
||||
|
||||
Программа для генерации тестов:
|
||||
|
||||
```cpp
|
||||
#include "testlib.h"
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
registerGen(argc, argv, 1);
|
||||
|
||||
int n = opt<int>(1); // Первый аргумент
|
||||
int maxVal = opt<int>(2); // Второй аргумент
|
||||
|
||||
std::cout << n << std::endl;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
std::cout << rnd.next(1, maxVal);
|
||||
if (i + 1 < n) std::cout << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**Использование:**
|
||||
```bash
|
||||
# В problem.xml указано:
|
||||
<test cmd="gen 1000 10000" method="generated"/>
|
||||
|
||||
# Polygon запускает:
|
||||
g.exe 1000 10000 > tests/05
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. **Checker (check.cpp)**
|
||||
|
||||
Программа для проверки корректности ответа.
|
||||
|
||||
**Типы checkers:**
|
||||
|
||||
#### **A. Стандартные (встроенные в testlib.h):**
|
||||
```cpp
|
||||
std::ncmp.cpp // Сравнение одного целого числа
|
||||
std::fcmp.cpp // Сравнение одного float с точностью
|
||||
std::wcmp.cpp // Сравнение по словам (tokens)
|
||||
std::lcmp.cpp // Построчное сравнение
|
||||
std::nyesno.cpp // Проверка YES/NO
|
||||
```
|
||||
|
||||
#### **B. Custom checker:**
|
||||
```cpp
|
||||
#include "testlib.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
registerTestlibCmd(argc, argv);
|
||||
|
||||
// inf - входной файл (input)
|
||||
// ouf - output участника (output user file)
|
||||
// ans - правильный ответ (answer)
|
||||
|
||||
int n = inf.readInt();
|
||||
|
||||
std::vector<int> jans(n);
|
||||
for (int i = 0; i < n; i++)
|
||||
jans[i] = ans.readInt();
|
||||
|
||||
std::vector<int> pans(n);
|
||||
for (int i = 0; i < n; i++)
|
||||
pans[i] = ouf.readInt();
|
||||
|
||||
// Проверка: порядок не важен (множества равны)
|
||||
std::sort(jans.begin(), jans.end());
|
||||
std::sort(pans.begin(), pans.end());
|
||||
|
||||
if (jans == pans)
|
||||
quitf(_ok, "Correct");
|
||||
else
|
||||
quitf(_wa, "Wrong answer");
|
||||
}
|
||||
```
|
||||
|
||||
**Exit codes:**
|
||||
- `0` - OK (правильный ответ) ✅
|
||||
- `1` - WA (неправильный ответ) ❌
|
||||
- `2` - PE (presentation error)
|
||||
- `3` - FAIL (ошибка в самом чекере)
|
||||
- `7` - Partial (частичный балл, для IOI-style)
|
||||
|
||||
---
|
||||
|
||||
### 6. **Validator (v.cpp)**
|
||||
|
||||
Проверяет корректность входных данных:
|
||||
|
||||
```cpp
|
||||
#include "testlib.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
registerValidation(argc, argv);
|
||||
|
||||
// Проверка формата входных данных
|
||||
int n = inf.readInt(1, 100000, "n"); // 1 ≤ n ≤ 100000
|
||||
inf.readEoln(); // Конец строки
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
inf.readInt(1, 1000000000, "a[i]");
|
||||
if (i + 1 < n) inf.readSpace();
|
||||
else inf.readEoln();
|
||||
}
|
||||
|
||||
inf.readEof(); // Конец файла
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**Назначение:**
|
||||
- Проверка ограничений (1 ≤ n ≤ 10⁶)
|
||||
- Проверка формата (пробелы, переводы строк)
|
||||
- Валидация структуры (дерево, граф и т.д.)
|
||||
|
||||
---
|
||||
|
||||
### 7. **Interactor (для интерактивных задач)**
|
||||
|
||||
Посредник между решением и тестирующей системой:
|
||||
|
||||
```cpp
|
||||
#include "testlib.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
registerInteraction(argc, argv);
|
||||
|
||||
int n = inf.readInt(); // Загаданное число
|
||||
|
||||
int queries = 0;
|
||||
while (queries < 20) {
|
||||
int guess = ouf.readInt(1, 1000000); // Запрос участника
|
||||
queries++;
|
||||
|
||||
if (guess == n) {
|
||||
tout << "YES" << endl;
|
||||
quitf(_ok, "Found in %d queries", queries);
|
||||
} else if (guess < n) {
|
||||
tout << ">" << endl; // Больше
|
||||
} else {
|
||||
tout << "<" << endl; // Меньше
|
||||
}
|
||||
}
|
||||
|
||||
quitf(_wa, "Too many queries");
|
||||
}
|
||||
```
|
||||
|
||||
**Streams в interactor:**
|
||||
- `inf` - входной файл (input)
|
||||
- `ouf` - output участника (чтение запросов)
|
||||
- `tout` - передача данных участнику (ответы на запросы)
|
||||
- `ans` - правильный ответ (не используется в интерактивных)
|
||||
|
||||
---
|
||||
|
||||
### 8. **Solutions (эталонные решения)**
|
||||
|
||||
**Типы решений:**
|
||||
|
||||
```xml
|
||||
<solution tag="main"> <!-- Главное решение (генерирует .a файлы) -->
|
||||
<solution tag="accepted"> <!-- Дополнительные AC решения -->
|
||||
<solution tag="wrong-answer"> <!-- WA (для теста checker'а) -->
|
||||
<solution tag="time-limit-exceeded"> <!-- TL -->
|
||||
<solution tag="memory-limit-exceeded"> <!-- ML -->
|
||||
<solution tag="rejected"> <!-- Другие RE/PE -->
|
||||
```
|
||||
|
||||
**Назначение:**
|
||||
- `main` - используется для генерации answer files
|
||||
- `accepted` - проверка, что задача решаема разными способами
|
||||
- `wrong-answer` - тестирование checker'а
|
||||
- `time-limit-exceeded` - проверка TL
|
||||
|
||||
---
|
||||
|
||||
### 9. **Grader-задачи (специальный тип)**
|
||||
|
||||
Участник пишет функцию, а не всю программу.
|
||||
|
||||
**Структура:**
|
||||
```
|
||||
files/
|
||||
├── aplusb.h ← Header с сигнатурой функции
|
||||
├── grader.cpp ← Main + вызов функции участника
|
||||
└── main.py ← Python wrapper
|
||||
|
||||
solutions/
|
||||
└── sol.cpp ← Реализация функции (не main!)
|
||||
```
|
||||
|
||||
**Пример:**
|
||||
```cpp
|
||||
// aplusb.h
|
||||
int sum(int a, int b);
|
||||
|
||||
// grader.cpp
|
||||
#include "aplusb.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
int a, b;
|
||||
std::cin >> a >> b;
|
||||
std::cout << sum(a, b) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// sol.cpp (решение участника)
|
||||
#include "aplusb.h"
|
||||
|
||||
int sum(int a, int b) {
|
||||
return a + b;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Статистика по примерам пакетов
|
||||
|
||||
### **a-plus-b-graders-7.zip:**
|
||||
```
|
||||
Размер: 2.4 MB
|
||||
Файлов: ~50
|
||||
Структура:
|
||||
✅ problem.xml
|
||||
✅ tests/ (8 тестов: 01-08, без .a файлов)
|
||||
✅ files/testlib.h
|
||||
✅ files/aplusb.h (grader header)
|
||||
✅ files/grader.cpp
|
||||
✅ files/g.cpp, g.exe (generator)
|
||||
✅ files/v.cpp, v.exe (validator)
|
||||
✅ check.cpp, check.exe (ncmp - числовой checker)
|
||||
✅ solutions/sol.cpp (main)
|
||||
✅ solutions/sol.py (accepted)
|
||||
✅ statements/english/ (условие)
|
||||
```
|
||||
|
||||
### **example-interactive-binary-search-26.zip:**
|
||||
```
|
||||
Размер: 10.7 MB
|
||||
Файлов: ~100+
|
||||
Структура:
|
||||
✅ problem.xml
|
||||
✅ tests/ (21 тест: 01-21, без .a файлов)
|
||||
✅ files/testlib.h
|
||||
✅ files/interactor.cpp, interactor.exe ← ИНТЕРАКТИВНАЯ!
|
||||
✅ files/gen.cpp, gen.exe
|
||||
✅ files/val.cpp, val.exe
|
||||
✅ check.cpp, check.exe
|
||||
✅ solutions/ (16 решений: main, ac, wa, tl, ml, pe, ...)
|
||||
✅ statements/english/ + russian/
|
||||
```
|
||||
|
||||
### **exam-queue-17.zip:**
|
||||
```
|
||||
Размер: 6.6 MB
|
||||
Файлов: ~80
|
||||
Структура:
|
||||
✅ problem.xml
|
||||
✅ tests/ (51 тест: 01-51, без .a файлов)
|
||||
✅ files/testlib.h
|
||||
✅ files/gen.cpp, gen.exe
|
||||
✅ files/val.cpp, val.exe
|
||||
✅ check.cpp, check.exe
|
||||
✅ solutions/ (множество решений)
|
||||
✅ statements/russian/ (только русское условие)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Ключевые выводы
|
||||
|
||||
### **Обязательные компоненты:**
|
||||
1. ✅ `problem.xml` - дескриптор
|
||||
2. ✅ `tests/` - тесты
|
||||
3. ✅ `files/testlib.h` - библиотека
|
||||
4. ✅ `solutions/` - хотя бы одно main решение
|
||||
|
||||
### **Опциональные (но часто присутствуют):**
|
||||
- `check.cpp` - custom checker (иначе используется wcmp)
|
||||
- `v.cpp` - validator
|
||||
- `g.cpp` - generator
|
||||
- `interactor.cpp` - для интерактивных задач
|
||||
- `statements/` - условия на разных языках
|
||||
- `*.a` файлы - ответы (генерируются из main solution)
|
||||
|
||||
### **Особенности формата:**
|
||||
- Входные файлы **БЕЗ расширения** (01, 02, не 01.in!)
|
||||
- Ответы с расширением `.a` (01.a, 02.a)
|
||||
- testlib.h - единая библиотека для всего
|
||||
- problem.xml - полное описание всего пакета
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Полезные ссылки
|
||||
|
||||
- **Polygon:** https://polygon.codeforces.com/
|
||||
- **testlib.h GitHub:** https://github.com/MikeMirzayanov/testlib
|
||||
- **Документация testlib:** https://codeforces.com/testlib
|
||||
- **Tutorial по Polygon:** https://codeforces.com/blog/entry/101072
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Поддержка в LiquidCode.Tester
|
||||
|
||||
Наша система **полностью поддерживает**:
|
||||
- ✅ Парсинг problem.xml
|
||||
- ✅ Тесты в формате tests/01, tests/01.a
|
||||
- ✅ Автоматическую генерацию answer файлов из main solution
|
||||
- ✅ Компиляцию и запуск custom checkers (testlib-based)
|
||||
- ✅ Определение лимитов времени/памяти из problem.xml
|
||||
- ✅ Поддержку всех основных языков (C++, Java, Python, C#, Kotlin)
|
||||
|
||||
**В разработке:**
|
||||
- ⏳ Поддержка interactor для интерактивных задач
|
||||
- ⏳ Поддержка grader-задач
|
||||
- ⏳ Запуск validator для проверки входных данных
|
||||
Reference in New Issue
Block a user