summaryrefslogtreecommitdiffstats
path: root/misc
diff options
context:
space:
mode:
authorDavid A. Madore <david+git@madore.org>2020-06-03 20:28:32 +0200
committerDavid A. Madore <david+git@madore.org>2020-06-03 20:28:32 +0200
commit95c305cfe98b74ff3ffa01f28e56229fa6c26c56 (patch)
tree7fde2023fe809baf9f228524e119bdb7e5d48374 /misc
parent65d4d206b348862f49f78df2814b274953a0495e (diff)
downloadinf105-95c305cfe98b74ff3ffa01f28e56229fa6c26c56.tar.gz
inf105-95c305cfe98b74ff3ffa01f28e56229fa6c26c56.tar.bz2
inf105-95c305cfe98b74ff3ffa01f28e56229fa6c26c56.zip
Start preparing multiple-choice test.
Diffstat (limited to 'misc')
-rwxr-xr-xmisc/randomize-test.pl179
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;
+}