djfz-2019/count-points.pl

341 lines
5.9 KiB
Perl
Executable File

#!/usr/bin/perl
use strict;
use utf8;
use TAP::Parser;
use Data::Dumper;
use Cwd;
binmode(STDOUT, ':utf8');
binmode(STDERR, ':utf8');
my %overrides = ();
if (-r 'overrides.txt') {
read_overrides();
}
my %to_hashes = map { $_ => 1 } split/\n/,<<'END_OF_HASHES';
2982763
2982861
2982882
2983113
2983141
2983337
3025421
3042368
3042564
3042571
3042613
3042697
3042704
3042732
3042753
3042774
3042788
3042795
3042865
3042893
3042907
3042949
3042963
3043040
3043047
3043061
3043082
3043110
3043124
3043145
3043180
3043187
3043194
3043208
3043215
3043362
3043432
3043439
3043488
3043502
3043516
3043537
3043579
3043607
3043628
3043635
3043649
3043656
3043684
3043761
3083822
3083885
3096331
END_OF_HASHES
my @reports = sort @ARGV;
my $total;
my %section_points = ('A' => 0, 'B' => 0, 'C' => 0);
my $student_id = get_student_id();
if (defined $student_id) {
print "STUDENT ID is $student_id\n";
} else {
print "UNKNOWN STUDENT ID\n";
}
intro();
for my $report (@reports) {
update_total($report, process_report($report));
}
outro($total);
sub get_student_id {
my $pwd = cwd();
if (my ($student_id) = ($pwd =~ m{-s(\d{5,7})(/arena)?})) {
return $student_id;
}
return undef;
}
sub update_total {
my ($report_file_path, $points) = @_;
my $section = get_section($report_file_path);
if (defined $section && $section ne 'A') {
if ($section_points{$section} > 0) {
print "UWAGA: TYLKO ZADANIE Z NAJWIĘKSZĄ LICZBĄ PUNKTÓW BĘDZIE LICZONE DLA DZIAŁU $section\n";
}
if ($points > $section_points{$section}) {
$total = $total - $section_points{$section} + $points;
$section_points{$section} = $points;
}
} else {
$total += $points;
}
}
sub get_section {
my ($report_file_path) = @_;
if (my ($section) = ($report_file_path =~ m{Task([ABC])})) {
return $section;
}
return undef;
}
sub get_failures_and_successes {
my ($file_path) = @_;
open my $tap_fh, $file_path or die $!;
my $tap_parser = TAP::Parser->new( { source => $tap_fh } );
while ( my $result = $tap_parser->next ) {
}
return (scalar($tap_parser->actual_failed), scalar($tap_parser->passed))
}
sub process_report {
my ($report_file) = @_;
my ($task_id) = ($report_file =~ m{^(.*)/report\.txt$});
my $override_key = get_override_key($student_id, $task_id);
if (exists $overrides{$override_key}) {
my $override_points = $overrides{$override_key};
print $task_id, " ", "FROM overrides.txt: ", $override_points, "\n";
return $override_points;
}
my ($nb_of_failures, $nb_of_successes) = get_failures_and_successes($report_file);
my $success = ($nb_of_failures == 0 && $nb_of_successes > 0);
my ($points, $deadline, $total, $remainder) = parse_description($task_id);
print $task_id, " ", ($success ? "PASSED" : "FAILED");
if (!check_deadline($task_id, $deadline)) {
$success = 0;
}
if (!check_if_the_right_task($student_id, $task_id, $total, $remainder)) {
print " WRONG TASK!";
$success = 0;
}
if (!$success) {
$points = 0;
}
if ($success) {
print " POINTS: $points";
}
print "\n";
return $points;
}
sub check_deadline {
my ($task_id, $deadline) = @_;
for my $file (glob "$task_id/*") {
if ($file !~ m{\.(in|arg|out|exp|\~)$|/(description\.txt|run)$}) {
my $last_timestamp = `(cd ../djfz-2019-s$student_id ; git log -1 --format=\%cd --date=iso $file 2> /dev/null)`;
if ($last_timestamp =~ m{\S}) {
chomp $last_timestamp;
if ($last_timestamp gt $deadline
and not ($task_id !~ m{Task(A|X0[123])}
and exists $to_hashes{$student_id * 7})) {
print " TOO LATE [$file: $last_timestamp later than $deadline]";
return 0;
}
}
}
}
return 1;
}
sub check_if_the_right_task {
my ($student_id, $task_id, $total, $remainder) = @_;
if (defined($total)) {
if ($student_id % $total != $remainder) {
return 0;
}
}
return 0 if $task_id =~ m{^TaskE} and not is_estudent($student_id);
return 0 if $task_id =~ m{^Task[AC]} and is_estudent($student_id);
return 1;
}
sub intro {
print_header();
print "SUMMARY\n\n";
}
sub outro {
my ($points) = @_;
print "\nTOTAL POINTS: $points\n";
open my $fh, '>', 'result.csv';
print $fh "POINTS\n";
print $fh $points, "\n";
close($fh);
print_header();
}
sub print_header {
print "=" x 20,"\n";
}
sub parse_description {
my ($task_id) = @_;
open my $fh, '<', "$task_id/description.txt" or die "???";
my $points = 0;
my $deadline = undef;
my $total = undef;
my $remainder = undef;
while (my $line=<$fh>) {
if ($line =~ m{^POINTS\s*:\s*(\d+)\s*$}) {
$points = $1;
} elsif ($line =~ m{^DEADLINE\s*:\s*(.*?)\s*$}) {
$deadline = $1;
} elsif ($line =~ m{^REMAINDER\s*:\s*(\d+)/(\d+)\s*$}) {
$remainder = $1;
$total = $2;
}
}
return ($points, $deadline, $total, $remainder);
}
sub read_overrides {
open my $fh, '<', 'overrides.txt';
while (my $line=<$fh>) {
chomp $line;
my ($id, $task, $points, $info) = split/\s+/,$line;
$overrides{get_override_key($id, "Task".$task)} = $points;
}
}
sub get_override_key {
my ($id, $task) = @_;
return $id.'+'.$task;
}
sub is_estudent {
my ($id) = @_;
my $suffix = substr($id, 1);
my %estudents = map { $_ => 1 } split/\n/,<<'END_OF_NUMBERS';
16136
21804
30291
30686
32746
32753
32754
32757
32759
32778
32813
32837
34595
34596
34598
34599
34603
34604
34608
34650
34654
39546
40549
42335
42611
42612
42613
42614
50169
50711
52484
84146
END_OF_NUMBERS
if ($estudents{$suffix}) {
return 1;
}
return 0;
}