From d4bbb3bb502da4c02c8507f77478bc6a5f2439c2 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Wed, 3 May 2017 21:28:23 +0000 Subject: mcexam (3may17) git-svn-id: svn://tug.org/texlive/trunk@44171 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/tex/latex/mcexam/mcexam.sty | 1897 +++++++++++++++++++++++++ 1 file changed, 1897 insertions(+) create mode 100644 Master/texmf-dist/tex/latex/mcexam/mcexam.sty (limited to 'Master/texmf-dist/tex/latex/mcexam') diff --git a/Master/texmf-dist/tex/latex/mcexam/mcexam.sty b/Master/texmf-dist/tex/latex/mcexam/mcexam.sty new file mode 100644 index 00000000000..d9f5838da2b --- /dev/null +++ b/Master/texmf-dist/tex/latex/mcexam/mcexam.sty @@ -0,0 +1,1897 @@ +%%% Copyright (c) 2017 Jorre Vannieuwenhuyze. +%%% +%%% Permission is granted to copy, distribute and/or modify this +%%% software under the terms of the LaTeX Project Public License +%%% (LPPL), version 1.3c or any later version. +%%% +%%% This software is provided 'as is', without warranty of any kind, +%%% either expressed or implied, including, but not limited to, the +%%% implied warranties of merchantability and fitness for a +%%% particular purpose. + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% SECTION 0. SET-UP PACKAGE +%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + + +%%% 0.1 Packages +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\RequirePackage{xkeyval} +\RequirePackage{etoolbox} +\RequirePackage{environ} +\RequirePackage{newfile} +\RequirePackage{enumitem} +\RequirePackage{longtable} +\RequirePackage{pgf} +\RequirePackage{xstring} + + + + + + + +%%% 0.2 Define package and options +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{mcexam}[2017/05/02 v0.3 LaTeX package for creating randomized Multiple Choice questions] + +% package option: output +\newbool{mc@concept} +\newbool{mc@exam} +\newbool{mc@key} +\newbool{mc@answers} +\newbool{mc@analysis} +\booltrue{mc@concept} +\def\mc@setAllOutputFalse{ + \boolfalse{mc@concept} + \boolfalse{mc@exam} + \boolfalse{mc@key} + \boolfalse{mc@answers} + \boolfalse{mc@analysis} + } +\define@key{mcexam.sty}{output}[concept]{ + \ifstrequal{#1}{concept} {\mc@setAllOutputFalse\booltrue{mc@concept} }{ + \ifstrequal{#1}{exam} {\mc@setAllOutputFalse\booltrue{mc@exam} }{ + \ifstrequal{#1}{key} {\mc@setAllOutputFalse\booltrue{mc@key} }{ + \ifstrequal{#1}{answers} {\mc@setAllOutputFalse\booltrue{mc@answers} }{ + \ifstrequal{#1}{analysis}{\mc@setAllOutputFalse\booltrue{mc@analysis}}{ + \PackageError{mcexam}{Invalid argument for package option output.}{Make sure the output type is either 'concept', 'exam', 'key', 'answers' or 'analysis'.} + }}}}}} + +% package option: number of versions +\def\mc@totalNumberOfVersions{4} +\define@key{mcexam.sty}{numberofversions}[4]{ + \ifnum0<#1\relax\else\PackageError{mcexam}{Invalid argument for package option numberofversions.}{Make sure the numberofversions is a positive integer.}\fi + \def\mc@totalNumberOfVersions{#1} + } + +% package option: version +\newcounter{mcversion} +\setcounter{mcversion}{1} +\newcommand\mc@theVersion{1} +\define@key{mcexam.sty}{version}[1]{ + \ifnum0<#1\relax\else\PackageError{mcexam}{Invalid argument for package option version.}{Make sure the version is a positive integer smaller than the total number of versions.}\fi + \ifnum\mc@totalNumberOfVersions<#1\relax\PackageError{mcexam}{Package option version too large.} + {Make sure the version is a positive integer smaller than the total number of versions.}\fi + \setcounter{mcversion}{#1} + \renewcommand\mc@theVersion{#1} + } + +% package option: seed +\define@key{mcexam.sty}{seed}[]{ + \ifnum0<#1\relax\else\PackageError{mcexam}{Invalid argument for package option seed.}{Make sure the seed is a positive integer}\fi + \pgfmathsetseed{#1} + } + +% package option: randomize questions +\newbool{mc@randomizeQuestions} +\booltrue{mc@randomizeQuestions} +\define@key{mcexam.sty}{randomizequestions}[true]{ + \ifstrequal{#1}{true}{\setbool{mc@randomizeQuestions}{#1}}{ + \ifstrequal{#1}{false}{\setbool{mc@randomizeQuestions}{#1}}{ + \PackageError{mcexam}{Invalid argument for package option randomizequestions.}{Make sure randomizequestions is either 'true' or 'false'.} + }}} + +% package option: randomize answers +\newbool{mc@randomizeAnswers} +\booltrue{mc@randomizeAnswers} +\define@key{mcexam.sty}{randomizeanswers}[true]{ + \ifstrequal{#1}{true}{\setbool{mc@randomizeAnswers}{#1}}{ + \ifstrequal{#1}{false}{\setbool{mc@randomizeAnswers}{#1}}{ + \PackageError{mcexam}{Invalid argument for package option randomizeanswers.}{Make sure randomizeanswers is either 'true' or 'false'.} + }}} + +% package option: write R file +\newbool{mc@writeRfile} +\booltrue{mc@writeRfile} +\define@key{mcexam.sty}{writeRfile}[true]{ + \ifstrequal{#1}{true}{\setbool{mc@writeRfile}{#1}}{ + \ifstrequal{#1}{false}{\setbool{mc@writeRfile}{#1}}{ + \PackageError{mcexam}{Invalid argument for package option writeRfile.}{Make sure writeRfile is either 'true' or 'false'.} + }}} + + +%%% Process Options +\def\mcexamoptions#1{\setkeys{mcexam.sty}{#1}} +\AtBeginDocument{\def\mcexamoptions#1{\PackageError{mcexam}{\protect\mcexamoptions\space can only be used in preamble.}{}}} +\ProcessOptionsX + + +%%%% Warning if neither answers nor questions are randomized +\AtBeginDocument{ + \ifboolexpr{bool{mc@randomizeQuestions} or bool{mc@randomizeAnswers}}{}{ + \PackageWarning{mcexam}{Neither questions nor answers are randomized!}{} + } + } + + + + +%%% 0.3 Set output booleans +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\newbool{mc@showPerVersion} +\newbool{mc@showQuestionPermutationtable} +\newbool{mc@showQuestionsAnalysis} +\newbool{mc@showQuestionList} +\newbool{mc@showCorrectAnswers} +\newbool{mc@showAnswerPoints} +\newbool{mc@showExplanation} +\newbool{mc@showAnswerPermutationTable} +\newbool{mc@showAnswersAnalysis} +\newbool{mc@showNotes} +\newbool{mc@showKeytable} + +\define@key{mc@show}{showPerVersion}[true]{ + \ifstrequal{#1}{true}{\booltrue{mc@showPerVersion}}{ + \ifstrequal{#1}{false}{\boolfalse{mc@showPerVersion}}{ + \PackageError{mcexam}{Invalid argument for showPerVersion.}{Make sure showPerVersion is either 'true' or 'false'.} + }}} +\define@key{mc@show}{showQuestionPermutationtable}[true]{ + \ifstrequal{#1}{true}{\booltrue{mc@showQuestionPermutationtable}}{ + \ifstrequal{#1}{false}{\boolfalse{mc@showQuestionPermutationtable}}{ + \PackageError{mcexam}{Invalid argument for showQuestionPermutationtable.}{Make sure showQuestionPermutationtable is either 'true' or 'false'.} + }}} +\define@key{mc@show}{showQuestionsAnalysis}[true]{ + \ifstrequal{#1}{true}{\booltrue{mc@showQuestionsAnalysis}}{ + \ifstrequal{#1}{false}{\boolfalse{mc@showQuestionsAnalysis}}{ + \PackageError{mcexam}{Invalid argument for showQuestionsAnalysis.}{Make sure showQuestionsAnalysis is either 'true' or 'false'.} + }}} +\define@key{mc@show}{showQuestionList}[true]{ + \ifstrequal{#1}{true}{\booltrue{mc@showQuestionList}}{ + \ifstrequal{#1}{false}{\boolfalse{mc@showQuestionList}}{ + \PackageError{mcexam}{Invalid argument for showQuestionList.}{Make sure showQuestionList is either 'true' or 'false'.} + }}} +\define@key{mc@show}{showCorrectAnswers}[true]{ + \ifstrequal{#1}{true}{\booltrue{mc@showCorrectAnswers}}{ + \ifstrequal{#1}{false}{\boolfalse{mc@showCorrectAnswers}}{ + \PackageError{mcexam}{Invalid argument for showCorrectAnswers.}{Make sure showCorrectAnswers is either 'true' or 'false'.} + }}} +\define@key{mc@show}{showAnswerPoints}[true]{ + \ifstrequal{#1}{true}{\booltrue{mc@showAnswerPoints}}{ + \ifstrequal{#1}{false}{\boolfalse{mc@showAnswerPoints}}{ + \PackageError{mcexam}{Invalid argument for showAnswerPoints.}{Make sure showAnswerPoints is either 'true' or 'false'.} + }}} +\define@key{mc@show}{showExplanation}[true]{ + \ifstrequal{#1}{true}{\booltrue{mc@showExplanation}}{ + \ifstrequal{#1}{false}{\boolfalse{mc@showExplanation}}{ + \PackageError{mcexam}{Invalid argument for showExplanation.}{Make sure showExplanation is either 'true' or 'false'.} + }}} +\define@key{mc@show}{showAnswerPermutationTable}[true]{ + \ifstrequal{#1}{true}{\booltrue{mc@showAnswerPermutationTable}}{ + \ifstrequal{#1}{false}{\boolfalse{mc@showAnswerPermutationTable}}{ + \PackageError{mcexam}{Invalid argument for showAnswerPermutationTable.}{Make sure showAnswerPermutationTable is either 'true' or 'false'.} + }}} +\define@key{mc@show}{showAnswersAnalysis}[true]{ + \ifstrequal{#1}{true}{\booltrue{mc@showAnswersAnalysis}}{ + \ifstrequal{#1}{false}{\boolfalse{mc@showAnswersAnalysis}}{ + \PackageError{mcexam}{Invalid argument for showAnswersAnalysis.}{Make sure showAnswersAnalysis is either 'true' or 'false'.} + }}} +\define@key{mc@show}{showNotes}[true]{ + \ifstrequal{#1}{true}{\booltrue{mc@showNotes}}{ + \ifstrequal{#1}{false}{\boolfalse{mc@showNotes}}{ + \PackageError{mcexam}{Invalid argument for showNotes.}{Make sure showNotes is either 'true' or 'false'.} + }}} +\define@key{mc@show}{showKeytable}[true]{ + \ifstrequal{#1}{true}{\booltrue{mc@showKeytable}}{ + \ifstrequal{#1}{false}{\boolfalse{mc@showKeytable}}{ + \PackageError{mcexam}{Invalid argument for showKeytable.}{Make sure showKeytable is either 'true' or 'false'.} + }}} + +\def\mcsetupConcept#1{\AtBeginDocument{\ifbool{mc@concept}{\setkeys{mc@show}{#1}}{}}} +\def\mcsetupExam#1{\AtBeginDocument{\ifbool{mc@exam}{\setkeys{mc@show}{#1}}{}}} +\def\mcsetupKey#1{\AtBeginDocument{\ifbool{mc@key}{\setkeys{mc@show}{#1}}{}}} +\def\mcsetupAnswers#1{\AtBeginDocument{\ifbool{mc@answers}{\setkeys{mc@show}{#1}}{}}} +\def\mcsetupAnalysis#1{\AtBeginDocument{\ifbool{mc@analysis}{\setkeys{mc@show}{#1}}{}}} + +\AtBeginDocument{\def\mcsetupConcept#1{\PackageError{mcexam}{\protect\mcsetupConcept can only be used in preamble.}{}}} +\AtBeginDocument{\def\mcsetupExam#1{\PackageError{mcexam}{\protect\mcsetupExam can only be used in preamble.}{}}} +\AtBeginDocument{\def\mcsetupKey#1{\PackageError{mcexam}{\protect\mcsetupKey can only be used in preamble.}{}}} +\AtBeginDocument{\def\mcsetupAnswers#1{\PackageError{mcexam}{\protect\mcsetupAnswers can only be used in preamble.}{}}} +\AtBeginDocument{\def\mcsetupAnalysis#1{\PackageError{mcexam}{\protect\mcsetupAnalysis can only be used in preamble.}{}}} + +\mcsetupConcept{showPerVersion=false + ,showQuestionPermutationtable=true + ,showQuestionsAnalysis=false + ,showQuestionList=true + ,showCorrectAnswers=true + ,showAnswerPoints=true + ,showExplanation=true + ,showAnswerPermutationTable=true + ,showAnswersAnalysis=false + ,showNotes=true + ,showKeytable=false + } +\mcsetupExam{showPerVersion=true + ,showQuestionPermutationtable=false + ,showQuestionsAnalysis=false + ,showQuestionList=true + ,showCorrectAnswers=false + ,showAnswerPoints=false + ,showExplanation=false + ,showAnswerPermutationTable=false + ,showAnswersAnalysis=false + ,showNotes=false + ,showKeytable=false + } +\mcsetupKey{showPerVersion=false + ,showQuestionPermutationtable=false + ,showQuestionsAnalysis=false + ,showQuestionList=false + ,showCorrectAnswers=false + ,showAnswerPoints=false + ,showExplanation=false + ,showAnswerPermutationTable=false + ,showAnswersAnalysis=false + ,showNotes=false + ,showKeytable=true + } +\mcsetupAnswers{showPerVersion=true + ,showQuestionPermutationtable=false + ,showQuestionsAnalysis=false + ,showQuestionList=true + ,showCorrectAnswers=true + ,showAnswerPoints=true + ,showExplanation=true + ,showAnswerPermutationTable=false + ,showAnswersAnalysis=false + ,showNotes=false + ,showKeytable=false + } +\mcsetupAnalysis{showPerVersion=false + ,showQuestionPermutationtable=true + ,showQuestionsAnalysis=true + ,showQuestionList=true + ,showCorrectAnswers=true + ,showAnswerPoints=true + ,showExplanation=true + ,showAnswerPermutationTable=true + ,showAnswersAnalysis=true + ,showNotes=true + ,showKeytable=false + } + + + + + + +%%% 0.4 Define \mcifoutput +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\newcommand\mcifoutput[3][]{ + \ifstrempty{#1}{}{\PackageError{mcexam}{\protect\mcifoutput\space cannot have optional version argument in preamble.}{}} + \gdef\mc@ifoutput@outputs{} + \renewcommand*\do[1]{ + \ifstrequal{##1}{concept}{\listgadd{\mc@ifoutput@outputs}{##1}}{ + \ifstrequal{##1}{key}{\listgadd{\mc@ifoutput@outputs}{##1}}{ + \ifstrequal{##1}{analysis}{\listgadd{\mc@ifoutput@outputs}{##1}}{ + \ifstrequal{##1}{exam}{\listgadd{\mc@ifoutput@outputs}{##1}}{ + \ifstrequal{##1}{answers}{\listgadd{\mc@ifoutput@outputs}{##1}}{ + \PackageWarning{mcexam}{Invalid output-type in \noexpand\mcifoutput: ##1. It is ignored.}{} + }}}}} + } + \docsvlist{#2} + \ifbool{mc@concept}{\ifinlist{concept}{\mc@ifoutput@outputs}{#3}{}}{} + \ifbool{mc@exam}{\ifinlist{exam}{\mc@ifoutput@outputs}{#3}{}}{} + \ifbool{mc@answers}{\ifinlist{answers}{\mc@ifoutput@outputs}{#3}{}}{} + \ifbool{mc@key}{\ifinlist{key}{\mc@ifoutput@outputs}{#3}{}}{} + \ifbool{mc@analysis}{\ifinlist{analysis}{\mc@ifoutput@outputs}{#3}{}}{} + } +\AtBeginDocument{\renewcommand\mcifoutput[3][]{ + \gdef\mc@ifoutput@versions{} + \renewcommand*\do[1]{ + \IfInteger{##1}{ + \ifnumcomp{0}{<}{##1}{ + \ifnumcomp{\mc@totalNumberOfVersions}{<}{##1}{ + \PackageWarning{mcexam}{Invalid version number in \noexpand\mcifoutput: ##1. It is ignored.}{} + }{\listgadd{\mc@ifoutput@versions}{##1}} + }{\PackageWarning{mcexam}{Invalid version number in \noexpand\mcifoutput: ##1. It is ignored.}{}} + }{\PackageWarning{mcexam}{Invalid version number in \noexpand\mcifoutput: ##1. It is ignored.}{}} + } + \docsvlist{#1} + \gdef\mc@ifoutput@outputs{} + \renewcommand*\do[1]{ + \ifstrequal{##1}{concept}{\listgadd{\mc@ifoutput@outputs}{##1}}{ + \ifstrequal{##1}{key}{\listgadd{\mc@ifoutput@outputs}{##1}}{ + \ifstrequal{##1}{analysis}{\listgadd{\mc@ifoutput@outputs}{##1}}{ + \ifstrequal{##1}{exam}{\listgadd{\mc@ifoutput@outputs}{##1}}{ + \ifstrequal{##1}{answers}{\listgadd{\mc@ifoutput@outputs}{##1}}{ + \PackageWarning{mcexam}{Invalid output-type in \noexpand\mcifoutput: ##1. It is ignored.}{} + }}}}} + } + \docsvlist{#2} + \ifbool{mc@concept}{\ifinlist{concept}{\mc@ifoutput@outputs}{ + \ifbool{mc@showPerVersion}{ + \ifstrempty{#1}{#3}{} + \xifinlist{\mc@theVersion}{\mc@ifoutput@versions}{#3}{} + }{#3} + }{}}{} + \ifbool{mc@exam}{\ifinlist{exam}{\mc@ifoutput@outputs}{ + \ifbool{mc@showPerVersion}{ + \ifstrempty{#1}{#3}{} + \xifinlist{\mc@theVersion}{\mc@ifoutput@versions}{#3}{} + }{#3} + }{}}{} + \ifbool{mc@answers}{\ifinlist{answers}{\mc@ifoutput@outputs}{ + \ifbool{mc@showPerVersion}{ + \ifstrempty{#1}{#3}{} + \xifinlist{\mc@theVersion}{\mc@ifoutput@versions}{#3}{} + }{#3} + }{}}{} + \ifbool{mc@key}{\ifinlist{key}{\mc@ifoutput@outputs}{ + \ifbool{mc@showPerVersion}{ + \ifstrempty{#1}{#3}{} + \xifinlist{\mc@theVersion}{\mc@ifoutput@versions}{#3}{} + }{#3} + }{}}{} + \ifbool{mc@analysis}{\ifinlist{analysis}{\mc@ifoutput@outputs}{ + \ifbool{mc@showPerVersion}{ + \ifstrempty{#1}{#3}{} + \xifinlist{\mc@theVersion}{\mc@ifoutput@versions}{#3}{} + }{#3} + }{}}{} + }} + + + + +%%% 0.5 Initialize internal package commands +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\newbool{mc@correct} +\newbool{mc@points} +\newcommand\mc@questionOption[1][]{} +\newcommand\mc@answerOption[1][]{} +\newcounter{mc@counter} +\newcounter{mc@mcquestions} +\newbox\mc@qbox +\newbox\mc@abox + + + + + + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% SECTION 1. MAIN COMMANDS +%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + +%%% 1.1 The mcquestions environment +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\NewEnviron{mcquestions}[1][]{ + %%% Save mcquestions option + \xdef\mc@mcquestionsOption{#1} + %%% Reset booleans for the marks + \global\boolfalse{mc@correct} + \global\boolfalse{mc@points} + %%% Set internal commands + \NewEnviron{mcquestioninstruction}{} + \NewEnviron{mcanswers}[1][]{} + \NewEnviron{mcanswerslist}[1][]{} + \NewEnviron{mcexplanation}{} + \NewEnviron{mcnotes}{} + %%% Processing commands + \mc@collectmcquestionsBody %%% SECTION 2 + \mc@setQuestionAndAnswerNumbers %%% SECTION 3 + \mc@writeRFile %%% SECTION 4 + \mc@typesetContent %%% SECTION 5 + } + + + + + + +%%% 1.2 Define lay-out of mcquestions +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\newcommand\mcversionlabelfmt[1]{\Roman{#1}} +\newcommand\mcquestionlabelfmt[1]{\arabic{#1}} +\newcommand\mcanswerlabelfmt[1]{(\alph{#1})} + +\newlist{setmcquestions}{enumerate}{1} +\setlist[setmcquestions]{label=\mcquestionlabelfmt{*}. + ,ref=\mcquestionlabelfmt{*} + ,itemsep=2\baselineskip + ,topsep=2\baselineskip + } + +\newlist{setmcanswerslist}{enumerate}{1} +\setlist[setmcanswerslist]{label=\mcanswerlabelfmt{*} + ,noitemsep + } + +\newlist{setmcquestioninfo}{description}{1} +\setlist[setmcquestioninfo]{before=\footnotesize\sffamily + } + +\newenvironment{setmcquestioninstruction}{ + \noindent + }{ + } +\newenvironment{setmcquestion}{ + }{ + } +\newenvironment{setmcanswers}{ + \vspace{\baselineskip} + }{ + } + +\newenvironment{setmcquestionpermutationtable}{ + \begin{center} + \footnotesize\sffamily + \setlength{\tabcolsep}{15pt} + }{ + \end{center} + } +\newenvironment{setmcanswerpermutationtable}{ + \begin{center} + \setlength{\tabcolsep}{10pt} + }{ + \end{center} + } + +\newenvironment{setmcquestionanalysistable}{ + \begin{center} + \setlength{\tabcolsep}{10pt} + \footnotesize\sffamily + }{ + \end{center} + } +\newenvironment{setmcansweranalysistable}{ + \begin{center} + \setlength{\tabcolsep}{10pt} + }{ + \end{center} + } + +\newenvironment{setmckeytable}{ + \begin{center} + \setlength{\tabcolsep}{10pt} + }{ + \end{center} + } + + + + +% %%% 1.3 Babel +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% English +\def\mc@babel@Concept@version{Concept version} +\def\mc@babel@Version{Version} +\def\mc@babel@Analysis{Analysis} +\def\mc@babel@Question{Question} +\def\mc@babel@Question@permutation@table{Question permutation table} +\def\mc@babel@Answer@permutations{Answer permutations} +\def\mc@babel@All@answers@permuted{All answers permuted} +\def\mc@babel@All@answers@permuted@except@last@answer{All answers permuted, except last answer} +\def\mc@babel@Order@of@answers@permuted{Order of answers permuted} +\def\mc@babel@No@answers@permuted{No answers permuted} +\def\mc@babel@Answers@permuted@by@user{Answers permuted by user} +\def\mc@babel@Answer{Answer} +\def\mc@babel@Correct@answers{Correct answers} +\def\mc@babel@Answer@points{Answer points} +\def\mc@babel@Explanation{Explanation} +\def\mc@babel@Analysis{Analysis} +\def\mc@babel@Notes{Notes} +\def\mc@babel@point{point} +\def\mc@babel@points{points} +\def\mc@babel@total{total} +\def\mc@babel@Proportion@correct{Proportion correct} +\def\mc@babel@Corrected@proportion{Corrected proportion correct} +\def\mc@babel@Mean@points{Mean points} +\def\mc@babel@Item@rest@correlation{Item-rest-correlation} +\def\mc@babel@Question@follows@previous{Question follows previous} +\def\mc@babel@pt{pt} +\def\mc@babel@pts{pts} +\def\mc@babel@Answer@Key{Answer Key} +\def\mc@babel@Answers{Answers} +\def\mc@babel@Mean{Mean} +\def\mc@babel@Proportion{Proportion} +\def\mc@babel@correct{correct} +\def\mc@babel@Corrected{Corrected} +\def\mc@babel@proportion{proportion} +\def\mc@babel@Item@rest{Item-rest} +\def\mc@babel@correlation{correlation} +\def\mc@babel@Number@of@students{Number of students} + +% Dutch +\AtBeginDocument{\@ifpackagewith{babel}{dutch}{ + \def\mc@babel@Concept@version{Concept versie} + \def\mc@babel@Version{Versie} + \def\mc@babel@Analysis{Analyse} + \def\mc@babel@Question{Vraag} + \def\mc@babel@Question@permutation@table{Vraag-permutatie tabel} + \def\mc@babel@Answer@permutations{Antwoord permutaties} + \def\mc@babel@All@answers@permuted{Alle antwoorden gerandomiseerd} + \def\mc@babel@All@answers@permuted@except@last@answer{Alle antwoorden gerandomiseerd, behalve de laatste} + \def\mc@babel@Order@of@answers@permuted{Volgorde van de antwoorden gerandomiseerd} + \def\mc@babel@No@answers@permuted{Antwoorden niet gerandomiseerd} + \def\mc@babel@Answers@permuted@by@user{Antwoorden gerandomiseerd door gebruiker} + \def\mc@babel@Answer{Antwoord} + \def\mc@babel@Correct@answers{Correcte antwoorden} + \def\mc@babel@Answer@points{Punten} + \def\mc@babel@Explanation{Uitleg} + \def\mc@babel@Analysis{Analyse} + \def\mc@babel@Notes{Nota's} + \def\mc@babel@point{punt} + \def\mc@babel@points{punten} + \def\mc@babel@total{totaal} + \def\mc@babel@Proportion@correct{Proportie correct} + \def\mc@babel@Corrected@proportion{Gecorrigeerde proportie correct} + \def\mc@babel@Mean@points{Gemiddelde punten} + \def\mc@babel@Item@rest@correlation{Item-rest-correlatie} + \def\mc@babel@Question@follows@previous{Vraag volgt op voorgaande} + \def\mc@babel@pt{pt} + \def\mc@babel@pts{ptn} + \def\mc@babel@Answer@Key{Antwoord Sleutel} + \def\mc@babel@Answers{Antwoorden} + \def\mc@babel@Mean{Gemiddelde} + \def\mc@babel@Proportion{Proportie} + \def\mc@babel@correct{juist} + \def\mc@babel@Corrected{Gecorrigeerde} + \def\mc@babel@proportion{proportie} + \def\mc@babel@Item@rest{Item-rest} + \def\mc@babel@correlation{correlatie} + \def\mc@babel@Number@of@students{Aantal studenten} + }{}} + + + + + + +%%% 1.4 Define \mctheversion +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\def\mctheversion{% + \ifbool{mc@concept}{\mc@babel@Concept@version\ifbool{mc@showPerVersion}{\ \mcversionlabelfmt{mcversion}}{}}{}% + \ifbool{mc@exam}{\ifbool{mc@showPerVersion}{\mc@babel@Version\ \mcversionlabelfmt{mcversion}}{}}{}% + \ifbool{mc@answers}{\mc@babel@Answers\ifbool{mc@showPerVersion}{\ \mc@babel@Version\ \mcversionlabelfmt{mcversion}}{}}{}% + \ifbool{mc@key}{\mc@babel@Answer@Key\ifbool{mc@showPerVersion}{\ \mc@babel@Version\ \mcversionlabelfmt{mcversion}}{}}{}% + \ifbool{mc@analysis}{\mc@babel@Analysis\ifbool{mc@showPerVersion}{\ \mc@babel@Version\ \mcversionlabelfmt{mcversion}}{}}{}% + } + + + + + + + + + + + + + + + + + + + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% SECTION 2. COMMANDS THAT COLLECT THE QUESTIONS AND ANSWERS +%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\def\mc@collectmcquestionsBody{ + \mc@collectmcquestionsBody@collectQuestions + \mc@collectmcquestionsBody@collectQuestioninstructions + \mc@collectmcquestionsBody@collectQuestionOptions + \mc@collectmcquestionsBody@collectAnswers + \mc@collectmcquestionsBody@checkPermutationtypes + \mc@collectmcquestionsBody@collectAnswerOptions + \mc@collectmcquestionsBody@collectExplanation + \mc@collectmcquestionsBody@collectNotes + } + + + +\def\mc@collectmcquestionsBody@collectQuestions{{ + %% collect the questions in control sequences mc@question1 to mc@questionN with N the number of questions + %% control sequences mc@question0 includes everything before the first mcquestion + \setcounter{mc@counter}{-1} + \DeclareListParser{\mc@collectQuestions}{\question} + \renewcommand\do[1]{ + \refstepcounter{mc@counter} + \long\csgdef{mc@question\arabic{mc@counter}}{\mc@questionOption##1} + } + \expandafter\mc@collectQuestions\expandafter{\expandafter\@empty\BODY} + %% Store the number of questions in \mc@totalNumberOfQuestions + \xdef\mc@totalNumberOfQuestions{\arabic{mc@counter}} + %% Give an error if environment doen't start with an \mcquestion or a \begin{mcquestioninstruction} + {{\RenewEnviron{mcanswers}[1][]{X} + \RenewEnviron{mcanswerslist}[1][]{X} + \RenewEnviron{mcexplanation}{X} + \RenewEnviron{mcnotes}{X} + \setbox0=\hbox{\csuse{mc@question0}\unskip} + \ifdim\wd0=0pt\else + \PackageError{mcexam}{Something's missing here! Add a \mcquestion or a \begin{questioninstruction}.} + {add a \mcquestion or a \begin{questioninstruction}...\end{questioninstruction} at the start of the mcquestions environment.} + \fi + }} + }} + + + +\def\mc@collectmcquestionsBody@collectQuestioninstructions{{ + %%% The mcquestioninstruction environments are stored in the previous mcquestion, we store them in seperate + %%% control sequences mc@questioninstruction1 to mc@questioninstructionN + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{{ + \csgdef{mc@questionInstruction\q}{} + \RenewEnviron{mcquestioninstruction}{ + \long\csxappto{mc@questionInstruction\q}{\expandonce\BODY} + } + \numdef\prevq{\q-1} + \setbox\mc@qbox\vbox{\csuse{mc@question\prevq}} + }} + %%% Give error if there is a mcquestioninstruction environment in last question + {{\RenewEnviron{mcquestioninstruction}{ + \PackageError{mcexam}{mcquestioninstruction after last question not allowed}{} + } + \setbox\mc@qbox\vbox{\csuse{mc@question\mc@totalNumberOfQuestions}} + }} + }} + + + +\def\mc@collectmcquestionsBody@collectQuestionOptions{{ + %%% check question options and collect in mc@questionOption1 to mc@questionOptionN + \setcounter{mc@counter}{0} + \renewcommand\mc@questionOption[1][]{ + \csxdef{mc@questionOption\q}{##1} + \ifcsempty{mc@questionOption\q}{ + \refstepcounter{mc@counter} + }{ + \ifcsstring{mc@questionOption\q}{follow}{ + \ifnumequal{\q}{1}{ + \PackageError{mcexam}{Question \q: invalid option for \protect\question, first question cannot follow}{} + }{} + }{ + \PackageError{mcexam}{Question \q: Invalid question option: should be 'follow' or empty}{} + } + } + } + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \setbox\mc@qbox\vbox{\csuse{mc@question\q}} + } + % Store the number of questionblocks in \mc@totalNumberOfQuestionblocks + \xdef\mc@totalNumberOfQuestionblocks{\arabic{mc@counter}} + }} + + + +\def\mc@collectmcquestionsBody@collectAnswers{{ + %%% collect the answers of mcanswers(list) environments for question 1 in control sequences mc@answerQ1A1 to mc@answerQ1AN + %%% with N the number of answers, answers for question 2 in control sequences mc@answerQ2A1 to mc@answerQ1AN, etc. + \DeclareListParser{\mc@collectAnswers}{\answer} + \renewcommand\do[1]{ + \refstepcounter{mc@counter} + \long\csgdef{mc@answerQ\q A\arabic{mc@counter}}{\mc@answerOption##1} + } + \RenewEnviron{mcanswerslist}[1][permuteall]{ + \ifnumcomp{\mc@check}{=}{1}{\PackageError{mcexam}{multiple mcanswers(list) environments defined for question \q}{}}{} + \gdef\mc@check{1} + \csgdef{mc@answerPermuteTypeQ\q}{##1} + \expandafter\mc@collectAnswers\expandafter{\expandafter\@empty\BODY} + \setbox0=\hbox{\csuse{mc@answerQ\q A0}\unskip} + \ifdim\wd0=0pt\else + \PackageError{mcexam}{Something's missing here! Add an \protect\answer\space in the answerlist environment of question \q.}{} + \fi + } + \RenewEnviron{mcanswers}[1][permuteall]{ + \ifnumcomp{\mc@check}{=}{1}{\PackageError{mcexam}{multiple mcanswers(list) environments defined for question \q}{}}{} + \gdef\mc@check{1} + \csgdef{mc@answerPermuteTypeQ\q}{##1} + \providecommand\answer[3][]{} + \renewcommand\answer[3][]{ + \IfInteger{####2}{}{\PackageError{mcexam}{Question \q: ####2\space is not a valid answer number in the \protect\answer\space command}{}} + \ifnumcomp{0}{<}{####2}{}{\PackageError{mcexam}{Question \q: ####2\space is not a valid answer number in the \protect\answer\space command}{}} + \listgadd\mc@answerVals{####2} + \ifnumcomp{\arabic{mc@counter}}{<}{####2}{\setcounter{mc@counter}{####2}}{} + \long\csgdef{mc@answerQ\q A####2}{\mc@answerOption[####1]####3} + } + \providecommand\answernum[1]{} + \renewcommand\answernum[1]{ + \IfInteger{####1}{}{\PackageError{mcexam}{Question \q: ####1\space is not a valid answer number in the \protect\answernum\space command}{}} + \ifnumcomp{0}{<}{####1}{}{\PackageError{mcexam}{Question \q: ####1\space is not a valid answer number in the \protect\answernum\space command}{}} + \listgadd\mc@answernumVals{####1} + \ifnumcomp{\arabic{mc@counter}}{<}{####1}{\setcounter{mc@counter}{####1}}{} + } + \setbox\mc@abox\vbox{\BODY} + \foreach \a in {1,...,\arabic{mc@counter}}{ + \xifinlist{\a}{\mc@answerVals}{}{\PackageError{mcexam}{Question \q: answer \a\space is not specified.}{}} + \xifinlist{\a}{\mc@answernumVals}{}{\PackageError{mcexam}{Question \q: answernum \a\space is not specified.}{}} + } + } + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \gdef\mc@check{0} + \setcounter{mc@counter}{-1} + \csgdef{mc@answerPermuteTypeQ\q}{} + \setbox\mc@qbox\vbox{\csuse{mc@question\q}} + \ifnum\mc@check=0 + \ifbool{mc@writeRfile} + { + \PackageError{mcexam}{No answers for question \q}{} + }{ + \PackageWarning{mcexam}{No answers for question \q}{} + } + \fi + \csxdef{mc@totalNumberOfAnswersQ\q}{\arabic{mc@counter}} + } + }} + + + +\def\mc@collectmcquestionsBody@checkPermutationtypes{{ +%%% Check mc@answerPermuteTypeQ1 to mc@answerPermuteTypeQN + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \ifcsempty{mc@answerPermuteTypeQ\q}{}{ + \ifcsstring{mc@answerPermuteTypeQ\q}{permuteall}{}{ + \ifcsstring{mc@answerPermuteTypeQ\q}{fixlast}{}{ + \ifcsstring{mc@answerPermuteTypeQ\q}{ordinal}{}{ + \ifcsstring{mc@answerPermuteTypeQ\q}{permutenone}{}{ + \setcounter{mc@counter}{0} + \renewcommand*{\do}[1]{ + \refstepcounter{mc@counter} + \csxdef{mc@userPermutationQ\q P\arabic{mc@counter}}{####1} + } + \letcs\@temp{mc@answerPermuteTypeQ\q} + \expandafter\docsvlist\expandafter{\@temp} + \csxdef{mc@totalNumberOfUserPermutationsQ\q}{\arabic{mc@counter}} + %Error if less than 2 permutation list defined + \ifnumcomp{\csuse{mc@totalNumberOfUserPermutationsQ\q}}{<}{2}{ + \PackageError{mcexam}{Question \q: invalid user defined permutation list, add at least two permutations}{} + }{} + %create a list with all values that should be in the permutation lists + \gdef\mc@checkAnswerValues{} + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \listxadd\mc@checkAnswerValues{\a} + } + \foreach \p in {1,...,\csuse{mc@totalNumberOfUserPermutationsQ\q}}{ + \letcs\@temp{mc@userPermutationQ\q P\p} + %check if all values in the permutations are valid answers + \renewcommand*{\do}[1]{ + \IfInteger{########1}{ + \ifnumcomp{########1}{>}{0}{ + \ifinlist{########1}{\mc@checkAnswerValues}{ + }{\PackageError{mcexam}{Question \q: ########1\space is not a valid permutation option, only \csuse{mc@totalNumberOfAnswersQ\q} answers present}{}} + }{\PackageError{mcexam}{Question \q: ########1\space is not a valid permutation option, should be a positive integer}{}} + }{\PackageError{mcexam}{Question \q: ########1\space is not a valid permutation option, should be an integer}{}} + } + \expandafter\docsvlist\expandafter{\@temp} + %check if there are not too many numbers in the permutation + \setcounter{mc@counter}{0} + \renewcommand*{\do}[1]{ + \refstepcounter{mc@counter} + } + \expandafter\docsvlist\expandafter{\@temp} + \ifnumcomp{\csuse{mc@totalNumberOfAnswersQ\q}}{<}{\arabic{mc@counter}}{\PackageError{mcexam}{Question \q: too many numbers in permutation \p}{}}{} + %check if all answer numbers are in the permutations + \def\mc@userpermvals{} + \renewcommand*{\do}[1]{\listadd\mc@userpermvals{########1}} + \expandafter\docsvlist\expandafter{\@temp} + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \expandafter\ifinlist\expandafter{\a}{\mc@userpermvals}{}{\PackageError{mcexam}{Question \q: answer \a\space is not in permutation \p}{}} + } + } + }}}}} + } + }} + + + + +\def\mc@collectmcquestionsBody@collectAnswerOptions{{ + %%% Check and save answer options in mc@answerOptionQ1A1 to mc@answerOptionQNAN + \renewcommand\mc@answerOption[1][]{ + \csgdef{mc@answerOptionQ\q A\a}{##1} + } + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \ifnum\csuse{mc@totalNumberOfAnswersQ\q}>0 + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \setbox\mc@abox\vbox{\csuse{mc@answerQ\q A\a}} + \ifcsempty{mc@answerOptionQ\q A\a}{}{ + \ifcsstring{mc@answerOptionQ\q A\a}{correct}{ + \ifbool{mc@points}{}{ + \global\booltrue{mc@correct} + } + }{ + \IfDecimal{\csuse{mc@answerOptionQ\q A\a}}{ + \global\boolfalse{mc@correct} + \global\booltrue{mc@points} + }{ + \PackageError{mcexam}{Question \q, answer \a: Invalid option, should be 'correct' or a number}{} + } + }} + } + \fi + } + }} + + + + + + + +\def\mc@collectmcquestionsBody@collectExplanation{{ + \RenewEnviron{mcexplanation}{ + \csxappto{mc@questionExplanationQ\q}{ + \expandonce\BODY + } + } + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \setbox\mc@qbox\vbox{\csuse{mc@question\q}} + } + }} + + + +\def\mc@collectmcquestionsBody@collectNotes{{ + \RenewEnviron{mcnotes}{ + \csxappto{mc@questionNotesQ\q}{ + \expandonce\BODY + } + } + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \setbox\mc@qbox\vbox{\csuse{mc@question\q}} + } + }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% 3. COMMANDS THAT GIVE THE QUESTIONS AND ANSWERS +%%% A (RANDOMIZED) ORDERED NUMBER +%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\def\mc@setQuestionAndAnswerNumbers{ + \mc@setQuestionNumbers %%% Subsection 3.1 + \mc@setAnswerNumbers %%% Subsection 3.2 + } + + + + +%%% 3.1 QUESTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\def\mc@setQuestionNumbers{ + \ifbool{mc@randomizeQuestions}{\mc@randomizeQuestions}{\mc@doNotRandomizeQuestions} + } + + +\def\mc@doNotRandomizeQuestions{{ + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \csxdef{mc@randomQuestionNumberV\v Q\q}{\q} + \csxdef{mc@originalQuestionNumberV\v Q\q}{\q} + } + } + }} + + +\def\mc@randomizeQuestions{{ + % Make the mcquestionblock control sequences which include macro's to set the randomization question counters + \setcounter{mc@counter}{0} + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \ifcsstring{mc@questionOption\q}{follow}{}{ + \refstepcounter{mc@counter} + \csgdef{mc@questionblock\arabic{mc@counter}}{} + } + \csxappto{mc@questionblock\arabic{mc@counter}}{ + \noexpand\refstepcounter{mc@counter} + \noexpand\csxdef{mc@randomQuestionNumberV\noexpand\v Q\q}{\noexpand\arabic{mc@counter}} + \noexpand\csxdef{mc@originalQuestionNumberV\noexpand\v Q\noexpand\arabic{mc@counter}}{\q} + } + } + % randomize question blocks + \numdef\@numberofswaps{\mc@totalNumberOfQuestionblocks-1} + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \foreach \q in {1,...,\@numberofswaps}{ + \pgfmathrandominteger{\r}{\q}{\@numberofswaps} + \numdef\r{\r+1} + \global\letcs\@swap{mc@questionblock\r} + \global\csletcs{mc@questionblock\r}{mc@questionblock\q} + \global\cslet{mc@questionblock\q}{\@swap} + } + \setcounter{mc@counter}{0} + \foreach \q in {1,...,\mc@totalNumberOfQuestionblocks}{ + \csuse{mc@questionblock\q} + } + } + }} + + + + + + + +%%% 3.2 ANSWERS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\def\mc@setAnswerNumbers{ + \ifbool{mc@randomizeAnswers}{\mc@randomizeAnswers }{\mc@doNotRandomizeAnswers } + } + + + +\def\mc@doNotRandomizeAnswers{ + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \ifnumgreater{\csuse{mc@totalNumberOfAnswersQ\q}}{0}{ + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \csxdef{mc@randomAnswerNumberV\v Q\q A\a}{\a} + \csxdef{mc@originalAnswerNumberV\v Q\q A\a}{\a} + } + } + }{} + } + } + + + +\def\mc@randomizeAnswers{ + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \ifnumgreater{\csuse{mc@totalNumberOfAnswersQ\q}}{0}{ + \ifcsempty{mc@answerPermuteTypeQ\q}{\mc@randomizeAnswers@permuteall}{ + \ifcsstring{mc@answerPermuteTypeQ\q}{permuteall}{\mc@randomizeAnswers@permuteall}{ + \ifcsstring{mc@answerPermuteTypeQ\q}{fixlast}{\mc@randomizeAnswers@fixlast}{ + \ifcsstring{mc@answerPermuteTypeQ\q}{ordinal}{\mc@randomizeAnswers@ordinal}{ + \ifcsstring{mc@answerPermuteTypeQ\q}{permutenone}{\mc@randomizeAnswers@permutenone}{ + \mc@randomizeAnswers@userdefined}}}}} + }{} + } + } + + + +\def\mc@randomizeAnswers@permuteall{ + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \csxdef{mc@answerTempnum\a}{\a} + } + \numdef\@numberofswaps{\csuse{mc@totalNumberOfAnswersQ\q}-1} + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \foreach \x in {1,...,\@numberofswaps}{ + \pgfmathrandominteger{\r}{\x}{\csuse{mc@totalNumberOfAnswersQ\q}} + \letcs\@temp{mc@answerTempnum\x} + \global\csletcs{mc@answerTempnum\x}{mc@answerTempnum\r} + \global\cslet{mc@answerTempnum\r}{\@temp} + } + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \csxdef{mc@randomAnswerNumberV\v Q\q A\a}{\csuse{mc@answerTempnum\a}} + \csxdef{mc@originalAnswerNumberV\v Q\q A\csuse{mc@answerTempnum\a}}{\a} + } + } + } + + + +\def\mc@randomizeAnswers@fixlast{ + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \csxdef{mc@answerTempnum\a}{\a} + } + \numdef\@numberofpermuteanswers{\csuse{mc@totalNumberOfAnswersQ\q}-1} + \numdef\@numberofswaps{\@numberofpermuteanswers-1} + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \foreach \x in {1,...,\@numberofswaps}{ + \pgfmathrandominteger{\r}{\x}{\@numberofpermuteanswers} + \letcs\@temp{mc@answerTempnum\x} + \global\csletcs{mc@answerTempnum\x}{mc@answerTempnum\r} + \global\cslet{mc@answerTempnum\r}{\@temp} + } + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \csxdef{mc@randomAnswerNumberV\v Q\q A\a}{\csuse{mc@answerTempnum\a}} + \csxdef{mc@originalAnswerNumberV\v Q\q A\csuse{mc@answerTempnum\a}}{\a} + } + } + } + + + +\def\mc@randomizeAnswers@ordinal{ + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \ifnumodd{\v}{\csgdef{mc@answerTempnum\v}{keep}}{\csgdef{mc@answerTempnum\v}{reorder}} + } + \numdef\@numberofswaps{\mc@totalNumberOfVersions-1} + \foreach \x in {1,...,\@numberofswaps}{ + \pgfmathrandominteger{\r}{\x}{\mc@totalNumberOfVersions} + \letcs\@temp{mc@answerTempnum\x} + \global\csletcs{mc@answerTempnum\x}{mc@answerTempnum\r} + \global\cslet{mc@answerTempnum\r}{\@temp} + } + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \ifcsstring{mc@answerTempnum\v}{keep}{ + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \csxdef{mc@randomAnswerNumberV\v Q\q A\a}{\a} + \csxdef{mc@originalAnswerNumberV\v Q\q A\a}{\a} + } + }{ + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \numdef\@temp{\csuse{mc@totalNumberOfAnswersQ\q}+1-\a} + \csxdef{mc@randomAnswerNumberV\v Q\q A\a}{\@temp} + \csxdef{mc@originalAnswerNumberV\v Q\q A\@temp}{\a} + } + } + } + } + + + +\def\mc@randomizeAnswers@permutenone{ + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \csxdef{mc@randomAnswerNumberV\v Q\q A\a}{\a} + \csxdef{mc@originalAnswerNumberV\v Q\q A\a}{\a} + } + } + } + + + +\def\mc@randomizeAnswers@userdefined{ + \numdef\@numberofswaps{\csuse{mc@totalNumberOfUserPermutationsQ\q}-1} + \gdef\mc@cntr{0} + \renewcommand*{\do}[1]{ + \global\numdef\a{\a+1} + \csxdef{mc@randomAnswerNumberV\v Q\q A\a}{##1} + \csxdef{mc@originalAnswerNumberV\v Q\q A##1}{\a} + } + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \ifnumequal{\mc@cntr}{0}{ + \foreach \p in {1,...,\@numberofswaps}{ + \pgfmathrandominteger{\r}{\p}{\csuse{mc@totalNumberOfUserPermutationsQ\q}} + \letcs\@temp{mc@userPermutationQ\q P\p} + \global\csletcs{mc@userPermutationQ\q P\p}{mc@userPermutationQ\q P\r} + \global\cslet{mc@userPermutationQ\q P\r}{\@temp} + } + }{} + \global\numdef\mc@cntr{\mc@cntr+1} + \gdef\a{0} + \letcs\@temp{mc@userPermutationQ\q P\mc@cntr} + \expandafter\docsvlist\expandafter{\@temp} + \ifnumequal{\mc@cntr}{\csuse{mc@totalNumberOfUserPermutationsQ\q}}{ + \gdef\mc@cntr{0} + }{} + } + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% 4. Create R file +%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\edef\@hashsign{\string#} +\edef\@lbracesign{\string{} +\edef\@rbracesign{\string}} +\newoutputstream{@Rfile} + +\def\mc@writeRFile{ + \ifbool{mc@writeRfile}{ + %%% specify the output file + \refstepcounter{mc@mcquestions} + \ifdefempty\mc@mcquestionsOption{ + \ifnumequal{\arabic{mc@mcquestions}}{1}{ + \xdef\mc@themcquestions{} + }{ + \xdef\mc@themcquestions{-\Alph{mc@mcquestions}} + } + }{ + \xdef\mc@themcquestions{-\mc@mcquestionsOption} + } + %%% Open the output file + \openoutputfile{\jobname\mc@themcquestions.r}{@Rfile} + \addtostream{@Rfile}{mcprocessanswers <- function(ID,versions,answers,path=getwd()) \@lbracesign } + \addtostream{@Rfile}{ } + %%% Options checks + \addtostream{@Rfile}{tol <- .Machine$double.eps^0.5 } + \addtostream{@Rfile}{if(! is.numeric(answers)) stop("non-numeric value(s) in answers, mcprocessanswers stopped") } + \addtostream{@Rfile}{if(min(answers > tol)==0) stop("non-positive value(s) in answers, mcprocessanswers stopped") } + \addtostream{@Rfile}{if(min(abs(answers - round(answers)) < tol)==0) stop("non-integer value(s) in answers, mcprocessanswers stopped") } + \addtostream{@Rfile}{if(! is.numeric(versions)) stop("non-numeric value(s) in versions, mcprocessanswers stopped") } + \addtostream{@Rfile}{if(min(versions > tol)==0) stop("non-positive value(s) in versions, mcprocessanswers stopped") } + \addtostream{@Rfile}{if(min(abs(versions - round(versions)) < tol)==0) stop("non-integer value(s) in versions, mcprocessanswers stopped") } + \addtostream{@Rfile}{if(min(versions-\mc@totalNumberOfVersions < tol)==0) stop("value(s) in versions too large, maximum possible value is \mc@totalNumberOfVersions, + mcprocessanswers stopped") } + \addtostream{@Rfile}{ } + %%% Write the question dictionary + \gdef\mc@tempV{} + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \gdef\mc@tempQ{} + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \ifdefempty\mc@tempQ{}{\xappto\mc@tempQ{,}} + \xappto\mc@tempQ{\csuse{mc@randomQuestionNumberV\v Q\q}} + } + \ifdefempty\mc@tempV{}{\xappto\mc@tempV{,}} + \xappto\mc@tempV{c(\mc@tempQ)} + } + \addtostream{@Rfile}{questiondictionary=list(\mc@tempV)} + \addtostream{@Rfile}{ } + %%% Write the answer dictionary + \addtostream{@Rfile}{randomizedanswersdictionary=list(} + \gdef\mc@temp{0} + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \gdef\mc@tempQ{} + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \gdef\mc@tempA{} + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \ifdefempty\mc@tempA{}{\xappto\mc@tempA{,}} + \xappto\mc@tempA{\csuse{mc@originalAnswerNumberV\v Q\q A\a}} + } + \ifdefempty\mc@tempQ{}{\xappto{\mc@tempQ}{,}} + \xappto{\mc@tempQ}{c(\mc@tempA)} + } + \ifdefstring\mc@temp{0}{ + \addtostream{@Rfile}{ list(\mc@tempQ)} + \gdef\mc@temp{1} + }{ + \addtostream{@Rfile}{ ,list(\mc@tempQ)} + } + } + \addtostream{@Rfile}{ )} + \addtostream{@Rfile}{ } + %%% Write points library + \gdef\mc@tempQ{} + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \gdef\mc@tempA{} + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\q}}{ + \ifdefempty\mc@tempA{}{\xappto\mc@tempA{,}} + \ifcsempty{mc@answerOptionQ\q A\a}{ + \xappto\mc@tempA{0} + }{ + \ifcsstring{mc@answerOptionQ\q A\a}{correct}{ + \xappto\mc@tempA{1} + }{ + \xappto\mc@tempA{\csuse{mc@answerOptionQ\q A\a}} + }} + } + \ifdefempty\mc@tempQ{}{\xappto\mc@tempQ{,}} + \xappto\mc@tempQ{c(\mc@tempA)} + } + \addtostream{@Rfile}{correctiondictionary=list(\mc@tempQ)} + \addtostream{@Rfile}{ } + %%% write number information + \addtostream{@Rfile}{Nversions=\mc@totalNumberOfVersions; } + \addtostream{@Rfile}{Nquestions=\mc@totalNumberOfQuestions;} + \gdef\mc@tempQ{} + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \ifdefempty\mc@tempQ{}{\xappto\mc@tempQ{,}} + \xappto\mc@tempQ{\csuse{mc@totalNumberOfAnswersQ\q}} + } + \addtostream{@Rfile}{Nanswers=c(\mc@tempQ);} + \addtostream{@Rfile}{Nstudents=nrow(answers);} + \addtostream{@Rfile}{ } + %%% determine answers to otiginal question, obtain points, calculate total + \addtostream{@Rfile}{Q <- matrix(NA,nrow=Nstudents,ncol=Nquestions); } + \addtostream{@Rfile}{P <- matrix(NA,nrow=Nstudents,ncol=Nquestions); } + \addtostream{@Rfile}{for ( student in 1:Nstudents )\@lbracesign } + \addtostream{@Rfile}{ for (question in 1:Nquestions)\@lbracesign } + \addtostream{@Rfile}{ R <- randomizedanswersdictionary[[versions[student]]][[question]]; } + \addtostream{@Rfile}{ Q[student,question] <- R[answers[student,questiondictionary[[versions[student]]][question]]]; } + \addtostream{@Rfile}{ P[student,question] <- correctiondictionary[[question]][Q[student,question]]; } + \addtostream{@Rfile}{ P[student,question] <- ifelse(is.na(P[student,question]),0,P[student,question]); } + \addtostream{@Rfile}{ \@rbracesign\@rbracesign } + \addtostream{@Rfile}{Points=apply(P,1,sum); } + \addtostream{@Rfile}{outputdata <- data.frame(ID=ID,versions=versions,originalQuestion=Q,pointsQuestion=P,total=Points); } + \addtostream{@Rfile}{ } + %%% Calculate mean of points + \addtostream{@Rfile}{p <- apply(P,2,mean); } + %%% Calculate corrected proportion correct + \ifbool{mc@correct}{ + \addtostream{@Rfile}{p.cor <- apply(P,2,mean) - (1-apply(P,2,mean))/(Nanswers-unlist(lapply(correctiondictionary,sum))); } + }{} + %%% Calculate item rest correlaction + \addtostream{@Rfile}{r.cor <- NULL; } + \addtostream{@Rfile}{for (i in 1:Nquestions)\@lbracesign } + \addtostream{@Rfile}{ r.cor[i] <- ifelse(var(P[,i])==0,0,cor(P[,i],apply(P[,-i],1,sum))); } + \addtostream{@Rfile}{ \@rbracesign } + \addtostream{@Rfile}{ } + %%% Calculate reliability + \addtostream{@Rfile}{Nquestions.cor <- sum(apply(P,2,var)>0); } + \addtostream{@Rfile}{alpha <- (Nquestions.cor/(Nquestions.cor-1))*(1-(sum(apply(P,2,var))/var(Points))); } + \addtostream{@Rfile}{ } + %%% Open output file .ana + \addtostream{@Rfile}{outputfilename=file.path(path,"\jobname.ana"); } + \addtostream{@Rfile}{write("\\makeatletter",outputfilename) ; } + \addtostream{@Rfile}{ } + %%% Write question analysis table + \addtostream{@Rfile}{formatnumber <- function(x) \@lbracesign } + \addtostream{@Rfile}{ y <- gsub("(?