summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--controle-2020qcm.tex117
-rwxr-xr-xmisc/randomize-test.pl183
2 files changed, 300 insertions, 0 deletions
diff --git a/controle-2020qcm.tex b/controle-2020qcm.tex
new file mode 100644
index 0000000..eef66e2
--- /dev/null
+++ b/controle-2020qcm.tex
@@ -0,0 +1,117 @@
+%% This is a LaTeX document. Hey, Emacs, -*- latex -*- , get it?
+\documentclass[12pt,a4paper]{article}
+\usepackage[francais]{babel}
+\usepackage[utf8]{inputenc}
+\usepackage[T1]{fontenc}
+%\usepackage{ucs}
+\usepackage{times}
+% A tribute to the worthy AMS:
+\usepackage{amsmath}
+\usepackage{amsfonts}
+\usepackage{amssymb}
+\usepackage{amsthm}
+%
+\usepackage{mathrsfs}
+\usepackage{wasysym}
+\usepackage{url}
+%
+\usepackage{graphics}
+\usepackage[usenames,dvipsnames]{xcolor}
+\usepackage{tikz}
+\usetikzlibrary{matrix,calc}
+\usepackage{hyperref}
+%
+%\externaldocument{notes-mitro206}[notes-mitro206.pdf]
+%
+\newenvironment{qcm}{\relax}{\relax}
+\newenvironment{qvar}{\relax}{\relax}
+\newcounter{quescnt}
+\newenvironment{question}%
+{\stepcounter{quescnt}\bigskip\noindent\textbf{Question~\arabic{quescnt}.}\par\nobreak}
+{\relax}
+\newcounter{answcnt}[quescnt]
+\newcommand\answer{%
+\stepcounter{answcnt}\smallskip\textbf{(\Alph{answcnt})}~}
+\let\rightanswer=\answer
+%
+\newcommand{\outnb}{\operatorname{outnb}}
+\newcommand{\downstr}{\operatorname{downstr}}
+\newcommand{\precs}{\operatorname{precs}}
+\newcommand{\mex}{\operatorname{mex}}
+\newcommand{\id}{\operatorname{id}}
+\newcommand{\limp}{\Longrightarrow}
+\newcommand{\gr}{\operatorname{gr}}
+\newcommand{\rk}{\operatorname{rk}}
+\newcommand{\fuzzy}{\mathrel{\|}}
+%
+\DeclareUnicodeCharacter{00A0}{~}
+%
+\DeclareMathSymbol{\tiret}{\mathord}{operators}{"7C}
+\DeclareMathSymbol{\traitdunion}{\mathord}{operators}{"2D}
+%
+\newif\ifcorrige
+\corrigefalse
+\def\seedval{test}
+%
+%
+%
+\begin{document}
+\ifcorrige
+\title{MITRO206\\Contrôle de connaissances — Corrigé\\{\normalsize Théories des jeux}}
+\else
+\title{MITRO206\\Contrôle de connaissances\\{\normalsize Théories des jeux}}
+\fi
+\author{}
+\date{26 juin 2020}
+\maketitle
+
+\pretolerance=8000
+\tolerance=50000
+
+\vskip1truein\relax
+
+\noindent\textbf{Consignes.}
+
+Ce contrôle de connaissances est un QCM (questionnaire à choix
+multiples). Chaque question admet une unique réponse correcte. Les
+questions sont totalement indépendantes les unes des autres. La
+sélection des questions et l'ordre ont été tirés aléatoirement et
+n'obéissent donc à aucune logique particulière.
+
+La réponse est attendue sous forme d'une liste de numéros de question
+suivie de la réponse proposée : par exemple, « \verb=1A 2B 4D= » pour
+signifier que la réponse proposée à la question 1 est (A), la réponse
+proposée à la question 2 est (B), et la réponse proposée à la
+question 4 est (D).
+
+Une réponse incorrecte sera (deux fois) plus fortement pénalisée
+qu'une absence de réponse : il est donc préférable de ne pas répondre
+à une question que de répondre aléatoirement.
+
+\medbreak
+
+Durée : 1h de 17h30 à 18h30
+
+\vfill
+
+\noindent
+Sujet généré pour : \texttt{\seedval}
+
+\medskip
+
+{\tiny\noindent
+\immediate\write18{sh ./vc > vcline.tex}
+Git: \input{vcline.tex}
+\immediate\write18{echo ' (stale)' >> vcline.tex}
+\par}
+
+\pagebreak
+
+\begin{qcm}
+
+
+\end{qcm}
+%
+%
+%
+\end{document}
diff --git a/misc/randomize-test.pl b/misc/randomize-test.pl
new file mode 100755
index 0000000..42ff144
--- /dev/null
+++ b/misc/randomize-test.pl
@@ -0,0 +1,183 @@
+#! /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 = (); # Preamble lines
+my @postamble = (); # Postamble lines
+my @questions = (); # Array of question hashrefs
+# Each question hash has keys:
+# {question}: arrayref with question lines
+# {answers}: arrayref of arrayrefs with answer lines, correct answer first
+# {varid}: idnex in qvars array
+my @qvars = (); # Array of question variants
+# Each entry is an arrayref of indexes in the questions array
+
+
+my $commonseed = $opts{N} // "";
+my $seed = $opts{n} // "";
+
+### 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/^\\def\\seedval\{.*\}$/ ) {
+ $_ = "\\def\\seedval\{$seed\}\n";
+ }
+ 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;
+ push @qvars, [];
+ 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;
+ 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 = ();
+ push @qvars, [] unless $in_qvar;
+ $qn{varid} = $#qvars;
+ $qn{question} = [];
+ $qn{answers} = [];
+ push @questions, \%qn;
+ push @{$qvars[$#qvars]}, $#questions;
+ $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);
+}
+
+}
+
+
+### RANDOMIZE
+
+my $nbqn = $opts{c} // int((scalar(@qvars)+1)/2);
+
+my @questab = ();
+my @quesanstab = ();
+
+if ( 1 ) { ## Keep following variables local
+
+my @hashlist;
+
+for ( my $u=0 ; $u<scalar(@qvars) ; $u++ ) {
+ push @hashlist, sha256("${commonseed}\n${seed}\nQV\n${u}\n");
+}
+my @qvartab = sort { $hashlist[$a] cmp $hashlist[$b] } (0..(scalar(@qvars)-1));
+
+for ( my $k=0 ; $k<scalar(@qvartab) && $k<$nbqn ; $k++ ) {
+ my $u = $qvartab[$k];
+ @hashlist = ();
+ for ( my $kv=0 ; $kv<scalar(@{$qvars[$u]}) ; $kv++ ) {
+ my $i = $qvars[$u]->[$kv];
+ push @hashlist, sha256("${commonseed}\n${seed}\nQ\n${i}\n");
+ }
+ my $kv = (sort { $hashlist[$a] cmp $hashlist[$b] } (0..(scalar(@{$qvars[$u]})-1)))[0];
+ my $i = $qvars[$u]->[$kv];
+ die "this is impossible" unless $questions[$i]->{varid} == $u;
+ 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 $kj=0 ; $kj<scalar(@{$quesanstab[$i]}) ; $kj++ ) {
+ my $j = $quesanstab[$i]->[$kj];
+ my $a = $qn->{answers}->[$j];
+ foreach my $l ( @{$a} ) {
+ print $l;
+ }
+ push @correct, sprintf("%d%s", $k+1, chr(ord("A")+$kj)) 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;
+}