diff options
| -rw-r--r-- | controle-2020qcm.tex | 117 | ||||
| -rwxr-xr-x | misc/randomize-test.pl | 183 | 
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; +} | 
