diff options
author | David A. Madore <david+git@madore.org> | 2020-06-03 20:28:32 +0200 |
---|---|---|
committer | David A. Madore <david+git@madore.org> | 2020-06-03 20:28:32 +0200 |
commit | 95c305cfe98b74ff3ffa01f28e56229fa6c26c56 (patch) | |
tree | 7fde2023fe809baf9f228524e119bdb7e5d48374 /misc | |
parent | 65d4d206b348862f49f78df2814b274953a0495e (diff) | |
download | inf105-95c305cfe98b74ff3ffa01f28e56229fa6c26c56.tar.gz inf105-95c305cfe98b74ff3ffa01f28e56229fa6c26c56.tar.bz2 inf105-95c305cfe98b74ff3ffa01f28e56229fa6c26c56.zip |
Start preparing multiple-choice test.
Diffstat (limited to 'misc')
-rwxr-xr-x | misc/randomize-test.pl | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/misc/randomize-test.pl b/misc/randomize-test.pl new file mode 100755 index 0000000..2db3998 --- /dev/null +++ b/misc/randomize-test.pl @@ -0,0 +1,179 @@ +#! /usr/local/bin/perl -w + +use strict; +use warnings; + +use Digest::SHA qw(sha256); + +use Getopt::Std; + +my %opts; + +getopts("c:N:n:", \%opts); + +my @preamble = (); +my @postamble = (); +my @questions = (); +my $nbvarid = 0; + + +### READ INPUT FILE + +if ( 1 ) { ## Keep following variables local + +my $in_preamble = 1; +my $in_postamble = 0; +my $in_qvar = 0; +my $curqn; +my $listref = \@preamble; +my $varid; +LINELOOP: +while ($_ = <>) { + if ( $_ =~ m/\\begin\{qcm\}/ ) { + die "wrong placement" unless $in_preamble; + die "bad format" unless $_ eq "\\begin\{qcm\}\n"; + $in_preamble = 0; + $listref = undef; + next LINELOOP; + } elsif ( $_ =~ m/\\end\{qcm\}/ ) { + die "wrong placement" if $in_preamble; + die "bad format" unless $_ eq "\\end\{qcm\}\n"; + $in_postamble = 0; + $listref = \@postamble; + next LINELOOP; + } elsif ( $_ =~ m/\\begin\{qvar\}/ ) { + die "wrong placement" if $in_preamble || $in_postamble || $in_qvar || defined($curqn); + die "bad format" unless $_ eq "\\begin\{qvar\}\n"; + $in_qvar = 1; + $varid = ($nbvarid++); + next LINELOOP; + } elsif ( $_ =~ m/\\end\{qvar\}/ ) { + die "wrong placement" if $in_preamble || $in_postamble || (!$in_qvar) || defined($curqn); + die "bad format" unless $_ eq "\\end\{qvar\}\n"; + $in_qvar = 0; + $varid = undef; + next LINELOOP; + } elsif ( $_ =~ m/\\begin\{question\}/ ) { + die "wrong placement" if $in_preamble || $in_postamble || defined($curqn); + die "bad format" unless $_ eq "\\begin\{question\}\n"; + my %qn = (); + $varid = ($nbvarid++) unless $in_qvar; + $qn{varid} = $varid; + $qn{question} = []; + $qn{answers} = []; + push @questions, \%qn; + $listref = $qn{question}; + $curqn = \%qn; + next LINELOOP; + } elsif ( $_ =~ m/\\end\{question\}/ ) { + die "wrong placement" if $in_preamble || $in_postamble || !defined($curqn); + die "bad format" unless $_ eq "\\end\{question\}\n"; + $listref = undef; + $curqn = undef; + next LINELOOP; + } elsif ( $_ =~ m/\\(right)?answer/ + && $_ !~ /\\newcommand/ && $_ !~ /\\let\\rightanswer/ ) { + die "wrong placement" if $in_preamble || $in_postamble || !defined($curqn); + die "bad format" unless $_ eq "\\answer\n" || $_ eq "\\rightanswer\n"; + die "this is impossible" unless ref($curqn) eq "HASH" && defined $curqn->{answers}; + die "right answer should come first" unless ($_ eq "\\rightanswer\n") == (scalar(@{$curqn->{answers}}) == 0); + my @ans = (); + push @{$curqn->{answers}}, \@ans; + $listref = \@ans; + ## no next LINELOOP here: include \answer in answer itself! + } + die "this is impossible" if $in_preamble && $in_postamble; + die "this is impossible" if $in_preamble && ($listref ne \@preamble); + die "this is impossible" if $in_postamble && ($listref ne \@postamble); + push @{$listref}, $_ if defined($listref); +} + +} + +# printf STDERR "nbvarid=%d (total=%d)\n", $nbvarid, scalar(@questions); + + +### RANDOMIZE + +my $commonseed = $opts{N} // ""; +my $seed = $opts{n} // ""; +my $nbqn = $opts{c} // int(($nbvarid+1)/2); + +my @questab = (); +my @quesanstab = (); + +if ( 1 ) { ## Keep following variables local + +my @hashlist; + +for ( my $i=0 ; $i<scalar(@questions) ; $i++ ) { + push @hashlist, sha256("${commonseed}\n${seed}\nQ\n${i}\n"); +} +my @prequestab = sort { $hashlist[$a] cmp $hashlist[$b] } (0..(scalar(@questions)-1)); +my %varid_punch; +PREQUESLOOP: +for ( my $k=0 ; $k<scalar(@prequestab) ; $k++ ) { + last if scalar(@questab) > $nbqn; + my $i = $prequestab[$k]; + my $qn = $questions[$i]; + my $varid = $qn->{varid}; + if ( defined($varid) ) { + if ( defined($varid_punch{$varid}) ) { + next PREQUESLOOP; + } else { + $varid_punch{$varid} = $i; + } + } + push @questab, $i; +} + +for ( my $i=0 ; $i<scalar(@questions) ; $i++ ) { + @hashlist = (); + my $r = $questions[$i]->{answers}; + for ( my $j=0 ; $j<scalar(@$r) ; $j++ ) { + push @hashlist, sha256("${commonseed}\n${seed}\nQ\n${i}\nA\n${j}\n"); + } + my @anstab; + @anstab = sort { $hashlist[$a] cmp $hashlist[$b] } (0..(scalar(@$r)-1)); + push @quesanstab, \@anstab; +} + +} + + +### WRITE OUTPUT FILE + +my @correct; + +foreach my $l ( @preamble ) { + print $l; +} + +print "\\begin\{qcm\}\n\n"; + +for ( my $k=0 ; $k<scalar(@questab) ; $k++ ) { + my $i = $questab[$k]; + my $qn = $questions[$i]; + print "\\begin\{question\}\n"; + foreach my $l ( @{$qn->{question}} ) { + print $l; + } + for ( my $kk=0 ; $kk<scalar(@{$quesanstab[$i]}) ; $kk++ ) { + my $j = $quesanstab[$i]->[$kk]; + my $a = $qn->{answers}->[$j]; + foreach my $l ( @{$a} ) { + print $l; + } + push @correct, sprintf("%d%s", $k+1, chr(ord("A")+$kk)) if $j==0; + } + print "\\end\{question\}\n\n"; +} + +print "\\end\{qcm\}\n\n"; + +printf "\%\% === %s ===\n", join(" ", @correct); +printf "\\ifcorrige\\bigskip\\noindent\\textbf{Corrigé.} %s\\fi\n", join(" ", @correct); + +foreach my $l ( @postamble ) { + print $l; +} |