Суть такая:
smart — быстрое, но в котором есть баг, который хотим найтиstupid — медленное, но точно корректноеgen — печатает какой-то корректный тест, сгенерированный случайноchecker, который n раз генерирует тест, даёт его на ввод stupid-у и smart-у, сравнивает выводы и останавливается, когда они отличаютсяЗадача. Есть массив чисел
Приведем код решения stupid, который будем использовать в качестве эталонного:
int a[maxn];
void stupid() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
int ans = 1e9;
for (int i = 0; i < n; i++)
ans = min(ans, a[i]);
cout << ans;
}Пусть у нас есть решение smart, которое содержит ошибку в границах цикла:
int a[maxn];
void smart() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
int ans = 1e9;
for (int i = 1; i < n; i++)
ans = min(ans, a[i]);
cout << ans;
}Даже в таком примере можно долго искать ошибку, если подбирать случайные тесты руками и проверять ответ на правильность, поэтому мы хотим найти тест, на котором два решения будут давать разный ответ, чтобы впоследствии найти ошибку в smart.
Примечание. Автор не рекомендует так делать, но многим такой подход кажется проще для понимания.
Суть в следующем:
int a[maxn];
int n;
int stupid() {
int n;
cin >> n;
int ans = 1e9;
for (int i = 0; i < n; i++)
ans = min(ans, a[i]);
return ans;
}
int smart() {
int n;
cin >> n;
int ans = 1e9;
for (int i = 1; i < n; i++)
ans = min(ans, a[i]);
return ans;
}
void gen() {
n = rand() % 10 + 1;
for (int i = 0; i < n; i++) {
a[i] = rand();
}
}
int main() {
for (int i = 0; i < 100; i++) {
gen();
if (smart() != stupid()) {
cout << "WA" << endl;
cout << n << endl;
for (int j = 0; j < n; j++) {
cout << a[j] << ' ';
}
break;
}
cout << "OK" << endl;
}
return 0;
}Суть в следующем:
Файлы stupid.cpp, smart.cpp и gen.py содержат уже понятный нам код.
Вот примерный код скрипта checker.py:
import os, sys
_, f1, f2, gen, iters = sys.argv # первый аргумент - 'checker.py' поэтому "откинем" его с помощью _
for i in range(int(iters)):
print('Test', i+1)
os.popen('python3 %s > test.txt' % gen)
v1 = os.popen('./%s < test.txt' % f1).readlines()
v2 = os.popen('./%s < test.txt' % f2).readlines()
if v1 != v2:
print("FAIL!\nInput:")
print(*(open("text.txt").readlines()))
print("Correct output:")
print(*v1)
print("Wrong output:")
print(*v2)
sys.exit()
print("No output differences found.")python3 checker.py stupid smart gen.py 100, предварительно скомпилировав stupid и smart в ту же директорию, что и сам checker.py.v1 != v2 следует использовать сторонний скрипт compare.py../» во всех системных вызовах и вместо “python3” писать “python”.Примечание. Ну такой вот примерно рецепт усредненный, потому что вариаций масса. Берется неправильное решение, оно не работает, рабочий код — это не про код моего бати. Он берет это решение, вываливает его в скрипт и начинает запускать. Добавляет огромное количество тестов, крайних случаев, рандома и МАКСТЕСТОВ! для проверки. Все это прогоняется вместе с медленным решением. Потом скрипт находит баг и системный блок остужается на балконе. Потом батя заносит тест и щедро заполнив код отладочным выводом начинает дебажить. При этом параллельно ест и засыпает крошками клавиатуру. Ест и приговаривает полушепотом ух ###. При этом у него на лбу аж пот выступает. Любезно мне иногда предлагает подебажить, но я отказываюсь. Надо ли говорить о том какой код получается потом? Вонища такая, что тестирующая система падает.