|
19 | 19 | #include <QDir> |
20 | 20 | #include <QFile> |
21 | 21 | #include <QFileInfo> |
| 22 | +#include <QRegularExpression> |
22 | 23 | #include <QTextStream> |
23 | 24 | #include <QTime> |
24 | 25 | #include <QUuid> |
@@ -449,7 +450,7 @@ void JudgingThread::compareRealNumbers(const QString &contestantOutput) { |
449 | 450 | fclose(standardOutputFile); |
450 | 451 | } |
451 | 452 |
|
452 | | -void JudgingThread::specialJudge(const QString &fileName) { |
| 453 | +void JudgingThread::lemonSpecialJudge(const QString &fileName) { |
453 | 454 | if (! QFileInfo::exists(inputFile)) { |
454 | 455 | score = 0; |
455 | 456 | result = FileError; |
@@ -564,6 +565,128 @@ void JudgingThread::specialJudge(const QString &fileName) { |
564 | 565 | result = CorrectAnswer; |
565 | 566 | } |
566 | 567 |
|
| 568 | +void JudgingThread::testlibSpecialJudge(const QString &fileName) { |
| 569 | + if (! QFileInfo::exists(inputFile)) { |
| 570 | + score = 0; |
| 571 | + result = FileError; |
| 572 | + message = tr("Cannot find standard input file"); |
| 573 | + return; |
| 574 | + } |
| 575 | + |
| 576 | + if (! QFileInfo::exists(fileName)) { |
| 577 | + score = 0; |
| 578 | + result = FileError; |
| 579 | + message = tr(R"(Cannot find contestant's output file)"); |
| 580 | + return; |
| 581 | + } |
| 582 | + |
| 583 | + if (! QFileInfo::exists(outputFile)) { |
| 584 | + score = 0; |
| 585 | + result = FileError; |
| 586 | + message = tr("Cannot find standard output file"); |
| 587 | + return; |
| 588 | + } |
| 589 | + |
| 590 | + auto judge = std::make_unique<QProcess>(this); |
| 591 | + QStringList arguments; |
| 592 | + arguments << inputFile << fileName << outputFile; |
| 593 | + judge->setStandardErrorFile(workingDirectory + "_score"); |
| 594 | + judge->start(Settings::dataPath() + task->getSpecialJudge(), arguments); |
| 595 | + |
| 596 | + if (! judge->waitForStarted(-1)) { |
| 597 | + score = 0; |
| 598 | + result = InvalidSpecialJudge; |
| 599 | + return; |
| 600 | + } |
| 601 | + |
| 602 | + QFile scoreFile(workingDirectory + "_score"); |
| 603 | + |
| 604 | + auto removeTempFiles = qScopeGuard([&] { scoreFile.remove(); }); |
| 605 | + |
| 606 | + QElapsedTimer timer; |
| 607 | + timer.start(); |
| 608 | + bool flag = false; |
| 609 | + |
| 610 | + while (timer.elapsed() < specialJudgeTimeLimit) { |
| 611 | + if (judge->state() != QProcess::Running) { |
| 612 | + flag = true; |
| 613 | + break; |
| 614 | + } |
| 615 | + |
| 616 | + QCoreApplication::processEvents(); |
| 617 | + |
| 618 | + if (stopJudging) { |
| 619 | + judge->kill(); |
| 620 | + return; |
| 621 | + } |
| 622 | + |
| 623 | + msleep(10); |
| 624 | + } |
| 625 | + |
| 626 | + if (! flag) { |
| 627 | + judge->kill(); |
| 628 | + score = 0; |
| 629 | + result = SpecialJudgeTimeLimitExceeded; |
| 630 | + return; |
| 631 | + } |
| 632 | + |
| 633 | + if (! scoreFile.open(QFile::ReadOnly)) { |
| 634 | + score = 0; |
| 635 | + result = InvalidSpecialJudge; |
| 636 | + return; |
| 637 | + } |
| 638 | + |
| 639 | + QTextStream scoreStream(&scoreFile); |
| 640 | + message = scoreStream.readAll(); |
| 641 | + |
| 642 | + score = 0; |
| 643 | + |
| 644 | + if (message.startsWith("ok")) { |
| 645 | + score = fullScore; |
| 646 | + } |
| 647 | + |
| 648 | + if (message.startsWith("FAIL")) { |
| 649 | + score = 0; |
| 650 | + result = InvalidSpecialJudge; |
| 651 | + return; |
| 652 | + } |
| 653 | + |
| 654 | + QRegularExpressionMatch m = QRegularExpression(R"(^partially correct \((\d+)\))").match(message); |
| 655 | + if (m.hasMatch()) { |
| 656 | + int val = m.captured(1).toInt(); |
| 657 | + score = val * fullScore / 100; |
| 658 | + } |
| 659 | + |
| 660 | + m = QRegularExpression(R"(^points ([0-9]*\.[0-9]+|[0-9]+))").match(message); |
| 661 | + if (m.hasMatch()) { |
| 662 | + double val = m.captured(1).toDouble(); |
| 663 | + score = val * fullScore; |
| 664 | + } |
| 665 | + |
| 666 | + if (scoreStream.status() == QTextStream::ReadCorruptData) { |
| 667 | + score = 0; |
| 668 | + result = InvalidSpecialJudge; |
| 669 | + return; |
| 670 | + } |
| 671 | + |
| 672 | + scoreFile.close(); |
| 673 | + |
| 674 | + if (score < 0) { |
| 675 | + score = 0; |
| 676 | + result = InvalidSpecialJudge; |
| 677 | + return; |
| 678 | + } |
| 679 | + |
| 680 | + if (score == 0) |
| 681 | + result = WrongAnswer; |
| 682 | + |
| 683 | + if (0 < score && score < fullScore) |
| 684 | + result = PartlyCorrect; |
| 685 | + |
| 686 | + if (score >= fullScore) |
| 687 | + result = CorrectAnswer; |
| 688 | +} |
| 689 | + |
567 | 690 | #ifdef Q_OS_WIN |
568 | 691 |
|
569 | 692 | QString getRandomString(int length) { |
@@ -1152,8 +1275,12 @@ void JudgingThread::judgeOutput() { |
1152 | 1275 | compareRealNumbers(fileName); |
1153 | 1276 | break; |
1154 | 1277 |
|
1155 | | - case Task::SpecialJudgeMode: |
1156 | | - specialJudge(fileName); |
| 1278 | + case Task::LemonSpecialJudgeMode: |
| 1279 | + lemonSpecialJudge(fileName); |
| 1280 | + break; |
| 1281 | + |
| 1282 | + case Task::TestlibSpecialJudgeMode: |
| 1283 | + testlibSpecialJudge(fileName); |
1157 | 1284 | break; |
1158 | 1285 | } |
1159 | 1286 | } |
@@ -1227,8 +1354,12 @@ void JudgingThread::judgeAnswersOnlyTask() { |
1227 | 1354 | compareRealNumbers(answerFile); |
1228 | 1355 | break; |
1229 | 1356 |
|
1230 | | - case Task::SpecialJudgeMode: |
1231 | | - specialJudge(answerFile); |
| 1357 | + case Task::LemonSpecialJudgeMode: |
| 1358 | + lemonSpecialJudge(answerFile); |
| 1359 | + break; |
| 1360 | + |
| 1361 | + case Task::TestlibSpecialJudgeMode: |
| 1362 | + testlibSpecialJudge(answerFile); |
1232 | 1363 | break; |
1233 | 1364 | } |
1234 | 1365 | } |
|
0 commit comments