diff options
author | Karl Berry <karl@freefriends.org> | 2017-05-03 21:28:23 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2017-05-03 21:28:23 +0000 |
commit | d4bbb3bb502da4c02c8507f77478bc6a5f2439c2 (patch) | |
tree | d219c8752ad2b3f4300cf5cb5cd1ee0378f7a271 /Master | |
parent | 4ca8bdfd37bd4cea0ec747539d231119e4e3a4eb (diff) |
mcexam (3may17)
git-svn-id: svn://tug.org/texlive/trunk@44171 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
-rw-r--r-- | Master/texmf-dist/doc/latex/mcexam/README.md | 9 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/mcexam/mcexam.pdf | bin | 0 -> 226175 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/mcexam/mcexam.tex | 662 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/mcexam/mcexam_example.tex | 319 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/mcexam/mcexam_example_dataset.r | 42 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/mcexam/mcexam.sty | 1897 | ||||
-rwxr-xr-x | Master/tlpkg/bin/tlpkg-ctan-check | 2 | ||||
-rw-r--r-- | Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc | 1 | ||||
-rw-r--r-- | Master/tlpkg/tlpsrc/mcexam.tlpsrc | 0 |
9 files changed, 2931 insertions, 1 deletions
diff --git a/Master/texmf-dist/doc/latex/mcexam/README.md b/Master/texmf-dist/doc/latex/mcexam/README.md new file mode 100644 index 00000000000..25b7148e087 --- /dev/null +++ b/Master/texmf-dist/doc/latex/mcexam/README.md @@ -0,0 +1,9 @@ +mcexam package v0.3 + +The mcexam package is a LaTeX package that automatically randomly permutes the order of questions and answer options in different versions of a multiple choice exam/test. Next to the exam versions themselves, the package also allows printing a concept version of the exam, a key table with the correct answers or points, and a document with solutions and explanation per exam version. The package also allows writing an R code which processes the results of the exam and calculates the grades. + +--------------- +Jorre Vannieuwenhuyze 2017 +jorre_v[ad]zoho.com + +Permission is granted to copy, distribute and/or modify this software under the terms of the LaTeX Project Public License, version 1.3c or later. diff --git a/Master/texmf-dist/doc/latex/mcexam/mcexam.pdf b/Master/texmf-dist/doc/latex/mcexam/mcexam.pdf Binary files differnew file mode 100644 index 00000000000..ce0ee651f84 --- /dev/null +++ b/Master/texmf-dist/doc/latex/mcexam/mcexam.pdf diff --git a/Master/texmf-dist/doc/latex/mcexam/mcexam.tex b/Master/texmf-dist/doc/latex/mcexam/mcexam.tex new file mode 100644 index 00000000000..c903a4d92d6 --- /dev/null +++ b/Master/texmf-dist/doc/latex/mcexam/mcexam.tex @@ -0,0 +1,662 @@ +%%% 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. + + +\documentclass{article} +\makeatletter +\renewcommand\tableofcontents{% + \@starttoc{toc}% +} +\makeatother + +\usepackage{parskip,enumitem} +\usepackage{fancyvrb} +\CustomVerbatimEnvironment{code}{Verbatim}{xleftmargin=1em} +\usepackage{url} + +\title{The \textsf{mcexam} package} +\author{Jorre Vannieuwenhuyze (\url{jorre_v@zoho.com})} + + + +\begin{document} +\sloppy +\maketitle + + + +{\small\noindent +This package automatically randomly permutes the order of questions and answer options in different versions of a multiple choice exam/test. Next to the exam versions themselves, the package also allows printing a concept version of the exam, a key table with the correct answers or points, and a document with solutions and explanation per exam version. The package also allows writing an R code which processes the results of the exam and calculates the grades.} + +\vspace{\stretch{1}} + +{\scriptsize\noindent\sffamily +Copyright \textcopyright\ 2017 Jorre Vannieuwenhuyze. Permission is granted to copy, distribute and/or modify this software under the terms of the LaTeX Project Public License, version 1.3c or later. +} + +\vspace{\stretch{1}} + +\tableofcontents + +\clearpage + + + + + +This package was developed for large-scale randomized multiple choice exams at my department. The functionalities of this package may overlap with the \textsf{esami} package and the \textsf{AMC} program but there were some special requirements at my department which are not included in these packages. In particular the \textsf{mcexam} provides the following features: +\begin{itemize} + \item The possible answer permutation patterns are completely flexible and can entirely be specified by the user. + \item Typesetting the answer options is completely flexible with the \verb+mcanswers+ environment. + \item At my university, the students have to fill in a standard one-page answer form and unprocessed results from these forms are directly provided to the examiner. The package writes an \verb+R+ code which processes and analyses these results. +\end{itemize} +It was easier to build this new package that fits our purpose than to unravel and change the existing ones. Nevertheless, in case of interest, it is my intention to contact the developers of the other packages in order to integrate the functionalities into one package. + +Specifying questions and answers with the \textsf{mcexam} are very straightforward and similar to ordinary list environments. Imagine that you want to develop a multiple choice exam with three questions, each including three possible answers, which all need to be randomized. With the \textsf{mcexam} package, all you need to do is to include these questions and answers in a list-wise structure within the \verb+mcquestions+ environment inside the document body of your favourite \LaTeX\ document-class: +\begin{code} +\begin{mcquestions} + +\question How much is $2+2$? + + \begin{mcanswerslist} + \answer two + \answer[correct] four + \answer five + \end{mcanswerslist} + +\question How much is $5-3$? + + \begin{mcanswerslist} + \answer 1 + \answer[correct] 2 + \answer 3 + \end{mcanswerslist} + +\question How much is $0 \times 2$? + + \begin{mcanswerslist}[fixlast] + \answer 1 + \answer 2 + \answer[correct] none of the above + \end{mcanswerslist} + +\end{mcquestions} +\end{code} + +Depending on the option you specify when loading the package, these questions can be compiled as +\begin{itemize} + \item a concept exam which includes all information about the randomizations and solutions; + \item each version of the exam itself; + \item a key table with the correct answers; + \item each version of the exam including the solutions and explanations; and + \item an analysis version which includes an analysis of the results of the exam after these are processed by \verb+R+. +\end{itemize} +The user of the package can further mark answer options by points instead of `correct/incorrect', group questions, add an introduction, an explanation and notes to each question, define arbitrary permutation patterns to the answers, and much more. As an example of such an option, note the optional argument \verb$fixlast$ in the \verb$mcanswerslist$ environment in the last question. This option means that the last answer in this question will never change place across different versions of the exam. Of course, there are many more such options and all these options are described below. + +An example exam file is given in \verb$mcexam_example.tex$. Fictitious results for this exam are given in the \verb$mcexam_example_dataset.r$ which can be processed in R following the instructions below. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +\section{Loading the package} + +The package is loaded as usual by the code statement +\begin{code}[commandchars=\!\?\;] +\usepackage[!emph?<options>;]{mcexam} +\end{code} +The \textsf{mcexam} package requires the following packages to be installed: +\textsf{xkeyval}, +\textsf{etoolbox}, +\textsf{xstring}, +\textsf{environ}, +\textsf{pgf}, +\textsf{enumitem}, +\textsf{longtable} and +\textsf{newfile}. + +The following package options can be included as `key=value'-pairs: + +\begin{itemize} + \item \verb$output$: + The package option \verb$output$ defines the output type of the document. There are five possible output types you can use: + \begin{itemize} + \item \verb$output=concept$: + This option creates a concept version of your exam with all the questions typeset in the same order as they appear in the script file. For each question, the correct answers or the answer points are given, a table is created with the answer permutations for each version of the exam, the explanation of the solution is shown and the additional notes are shown. \verb$concept$ is the default output type. + \item \verb$output=exam$: + This option creates a version of the exam that can be printed and given to the students during the real exam. It doesn't mark the correct answer and hides explanation boxes and question notes. The version of the exam which needs to be made, can be specified by the \verb$version$ option (see below). + \item \verb$output=key$: + This option creates a key table with the labels of the correct answers for each question. This key table can be published after the exam so that the students can check there answers, without seeing the actual questions and answers themselves. + \item \verb$output=answers$: + This option creates a document with the questions, the answers and an explanation of the solution. It is meant to be used for feedback to the students. As with the \verb+exam+ output, these answer documents have to be made for each version separately because they maintain the randomization order of the questions and answers. The version of the exam which needs to be made, can be specified by the \verb$version$ option (see below). + \item \verb$output=analysis$: + This option provides an analysis of the results, it provides the frequencies of students giving the answer options and it shows statistics like the average points, the p-value, the corrected p-value, the item rest correlation, or Cronbach's alpha. Before using this option, the results need to be processed by R first (see section \ref{sec:analysis}). + \end{itemize} + + + \item \verb$numberofversions=$$n$: + This option specifies the total number of versions $n$ to be made. By default the number of versions is set to $4$. Make sure that the version number (the next package option) does not exceed this number. If the version number does exceed the number of versions, an error will be thrown. + + \item \verb$version=$$v$: + This option defines the version $v$ which needs to be printed when \verb$output=exam$ or \verb$output=answers$. This option takes a number as argument between 1 and the total number of versions, e.g. \verb$version=1$, \verb$version=2$, etc. The default value of this option is \verb$version=1$. + + The package also defines the command \verb+\mctheversion+ which can be used to print the version number on the document in the correct format (see section \ref{section:counterformats}). In the \verb$exam$ or \verb$answers$ output style, it prints ``Version $v$''. In the \verb$concept$ output style, it prints ``Concept version''. In the \verb$analysis$ output style, it prints ``Analysis''. + + \item \verb$seed=$$s$: + This option sets the seed $s$ for the random permutations, which is an arbitrarily chosen positive integer. The seed is not set by default, which means that a different randomization will be obtained each time the document is processed. For that reason, it is advised to always specify the seed, in order to obtain consistent output across different runs. + + \item \verb$randomizequestions=$\emph{true/false}: + This option defines whether the question order should be randomized (true) or not (false). This option is set to true by default. + + \item \verb$randomizeanswers=$\emph{true/false}: + This option defines whether the answer order should be randomized (true) or not (false). This option is set to true by default. If you set both the \verb$randomizequestions$ and the \verb$randomizeanswers$ options to false, a warning will be thrown. After all, if you don't want to randomize anything, you don't really need this package. + + \item \verb$writeRfile=$\emph{true/false}: + This option defines whether an \verb$R$-script should be written including macro's to process and analyse the students' answers. If it is set to true, an \verb$R$-script will be written. By default it is set to false. Note that, if this option is set to true, all questions should contain answers within the \verb+mcanswers+ or \verb+mcanswerslist+ environments, otherwise the program will throw errors. + +\end{itemize} + +The package also defines the \verb$\mcexamoptions{key=value,...}$ command which can also be used to set or change the package options after the package has been loaded. + + + + + + + + + + + + + + + + + + + + +\section{Setting the questions} + + +\subsection{The questions} + +The most important parts of the exam are, of course, the questions. Within the body of your script file, you place the questions within the \verb$mcquestions$-environment which works similar to list-environments. Each question is preceded by a \verb$\question$ command similar to the \verb$\item$ command : +\begin{code} +\begin{mcquestions} +\question This is the first question. +\question This is the second question. +\end{mcquestions} +\end{code} + +Sometimes, some questions belong together and these questions may not be split when the question order is randomized. To avoid this undesirable behavior, you can include \verb$follow$ as an optional argument to the \verb$\question$ command. For example, +\begin{code} +\begin{mcquestions} +\question This is the first question. +\question[follow] This is the second question. +\question The third question. +\end{mcquestions} +\end{code} +means that the second question will always directly follow the first question even though they may appear as questions two and three instead of one and two in some versions of the exam. + + + + + +\subsection{The answers} + +With the \verb$mcexam$ package, answers can be set in two ways. The first and probably the most common way to set the answers is a list structure. This can be achieved by the \verb$mcanswerslist$ environment which works similar to regular list-environments. Each answer is preceded by an \verb$\answer$ command (like \verb$\item$ in an \verb$itemize$ list). You can include as many answers as you want. For example +\begin{code} +\question What is the color of the sky? + \begin{mcanswerslist} + \answer blue + \answer green + \answer red + \answer yellow + \answer none of the above + \end{mcanswerslist} +\end{code} +will typeset +\begin{enumerate}[label=\arabic{*}.,itemsep=1\baselineskip] + \item What is the color of the sky? + \begin{enumerate}[label=\alph{*}),noitemsep] + \item blue + \item green + \item red + \item yellow + \item none of the above + \end{enumerate} +\end{enumerate} +or any of its permutations. + +Sometimes, however, such list structures are not what you want. In that case you can use the \verb$mcanswers$ environment. Within this environment you need to use the \verb$\answer$ command and the \verb$\answernum$ command. The \verb$\answer{$$n$\verb$}{$\emph{answer}\verb$}$ sets the \emph{answer} itself which is assigned number $n$. It is mandatory to use all numbers between 1 and the total number of answers. For example, if you need three answers you need to include \verb$\answer{1}{...}$, \verb$\answer{2}{...}$, and \verb$\answer{3}{...}$, otherwise the package will throw errors. The order in which the \verb$\answer$ commands appear, however, is not important. You can start with \verb$\answer{3}{...}$ as long as you also include \verb$\answer{1}{...}$ and \verb$\answer{2}{...}$. + +The \verb$\answernum{$$n$\verb$}$ simply typesets the answer number $n$ in the correct format (see section \ref{section:counterformats}). This command is not mandatory to use, but it is highly recomended to use it because it will automatically typeset the answer number in the correct format. + +As an example, the code +\begin{code} +\question Which is the letter alpha? + \begin{mcanswers} + \begin{tabular}{cccc} + \answer{1}{\Huge$\alpha$} & + \answer{2}{\Huge$\beta$} & + \answer{3}{\Huge$\gamma$} & + \answer{4}{\Huge$\delta$} \\[0.1\baselineskip] + \answernum{1} & + \answernum{2} & + \answernum{3} & + \answernum{4} \\ + \end{tabular} + \end{mcanswers} +\end{code} +will produce +\begin{enumerate}[label=\arabic{*}.,itemsep=1\baselineskip] + \item Which is the letter alpha?\par + \begin{tabular}{cccc} + \Huge$\alpha$&\Huge$\beta$&\Huge$\gamma$&\Huge$\delta$\\[0.1\baselineskip] + a)&b)&c)&d)\\ + \end{tabular} +\end{enumerate} +or something similar with the Greek letters shuffled around. + + + + + + +\subsubsection{Permuting the answers} + +By default, all answers are randomly shuffled within the \verb$mcanswerslist$ and \verb$mcanswers$ environments. However, this is not always what you want. For that reason, both environments have one optional argument which specifies how answers should be permuted. This option can be one of the following: +\begin{itemize} + \item \verb$permuteall$: + With this option, all answers are permuted in the different versions of the exam. This is the default option and doesn't need to be given explicitly. + \item \verb$ordinal$: + This option permutes the answers in order. That is, the answers are given on the exam either in the order or the reversed order as they are given in the script file. + \item \verb$fixlast$: + This option permutes all answers except the last given answer. This is handy if the last answer is something like, for example, ``None of the above''. + \item \verb$permutenone$: + This option doesn't permute the answers and sorts the answers in each version in the same order as they are given in the script file. + \item \emph{User specific}: + If none of the above options satisfies your needs, you can still enter the possible permutations manually. You achieve this by making a comma separated list of all allowed permutations where each permutation itself is a comma separated list of all answer numbers within two curly braces. For example, if your question contains three answers you can give the option \verb$[{1,2,3},{2,3,1}]$. With this option, the package will either put the answers in the order `answer 1, answer 2, answer 3' or in the order `answer 2, answer 3, answer 1'. The package will throw errors if only one permutation is given, if a permutation does not contain all answer numbers, if a permutations contains answer numbers more than once, or if a permutation contains invalid answer numbers. The package will not throw errors if a permutation is given more than once. For example, \verb$[{1,2,3},{1,2,3},{2,3,1}]$ will not give errors, it just means that the order `1,~2,~3' is twice more likely to appear than the order `2,~3,~1'. +\end{itemize} + +Putting all together, in your script file you can write something like this: +\begin{code} +\question What is the color of the sky? + \begin{mcanswerslist}[fixlast] + \answer blue + \answer green + \answer red + \answer yellow + \answer none of the above + \end{mcanswerslist} + +\question Which statement is correct? + \begin{mcanswerslist}[{1,2,3,4},{2,1,4,3} + ,{3,4,1,2},{4,3,2,1}] + \answer The moon is a planet. + \answer The moon is a star. + \answer The sun is a planet. + \answer The sun is a star. + \end{mcanswerslist} +\end{code} + + + + + +\subsubsection{Points} + +The correct answer (or answers) can be marked by an optional argument of the \verb$\answer$ command in both the \verb$mcanswerslist$ and \verb$mcanswers$ environments, that is +\begin{code}[commandchars=\!\?\;] +\answer[!emph?<mark>;] +\end{code} +in the \verb$mcanswerslist$ environment and +\begin{code}[commandchars=\!\?\;] +\answer[!emph?<mark>;]{!emph?<n>;}{!emph?<answer>;} +\end{code} +in the \verb$mcanswers$ environment. The \textit{\texttt{<mark>}}-option can be either of two modes. +\begin{itemize} + \item \verb$correct$ or empty (=incorrect, default): + With these options, answers are either correct or incorrect. Correct answers are given one point, incorrect answers are given zero points. Note that more than one answer per question can be marked as correct. + \item A decimal number: + Altenatively, the marks can be decimal numbers which are the points given to each answer. The numbers/points can be negative in case you want to use guess corrections. +\end{itemize} +Depending on the mode (correct/incorrect or points) the package may give slightly different output in some output types. As soon as the package encounters one decimal as a mark, it switches to points mode. In this mode, \verb$correct$ or empty options will not give errors but will be treated as one point and zero points respectively. In case no decimal marks are given and only `\verb$correct$' marks are encountered, the package will give output in correct/incorrect-mode. + +As an example, the following questions are valid questions: +\begin{code} +\question Which is the letter alpha? + \begin{mcanswers} + \begin{tabular}{cccc} + \answer[correct]{1}{\Huge$\alpha$} & + \answer{2}{\Huge$\beta$} & + \answer{3}{\Huge$\gamma$} & + \answer{4}{\Huge$\delta$} \\[0.1\baselineskip] + \answernum{1}& + \answernum{2}& + \answernum{3}& + \answernum{4}\\ + \end{tabular} + \end{mcanswers} +\end{code} +and +\begin{code} +\question What is the color of the sky? + \begin{mcanswerslist}[fixlast] + \answer[4] blue + \answer[-2] green + \answer[1.5] red + \answer[1] yellow + \answer none of the above + \end{mcanswerslist} +\end{code} + + + + + + + + + + +\subsection{Instructions, explanation, and notes} + + +Additional to the answers, the question environment can also include an \verb$mcquestioninstruction$, an \verb$mcexplanation$ and an \verb$mcnotes$ environment. The \verb$mcquestioninstruction$ environment is used for general instructions about the next question or group of questions (using the \verb$follow$ option of the \verb$\question$ command). It is printed in the exams themselves. The \verb$mcexplanation$ enviromnent should be used to store an explanation of the question and the right answer. It is printed in the \verb$concept$ and the \verb$answers$ versions. The \verb$mcnotes$ enviromnent, in contrast, can be used to store additional notes about the question. It is only printed in the \verb$concept$ version. An example of their use is as follows: +\begin{code} +\begin{mcquestioninstruction} +This is a question about the sky. +\end{mcquestioninstruction} + +\question What is the color of the sky? + + \begin{mcanswerslist}[fixlast] + \answer[4] blue + \answer[-2] green + \answer[1.5] red + \answer[1] yellow + \answer none of the above + \end{mcanswerslist} + + \begin{mcexplanation} + If you look up to the sky and there are no clouds, + you'll see it is blue. + \end{mcexplanation} + + \begin{mcnotes} + This question had a large proportion of good answers + last year. + \end{mcnotes} +\end{code} + +Note that the \verb$mcquestioninstruction$ comes before the \verb$\question$ command while the \verb$mcexplanation$ and \verb$mcnotes$ environments come after the \verb$\question$ command. As a result, an \verb$mcexplanation$ or an \verb$mcnotes$ environment before the first \verb$\question$ will give an error, while an \verb$mcquestioninstruction$ after the last \verb$\question$ will also give an error. + + + + +\section{Selective output} + +Sometimes, you may want to print some text or use some commands in, for example, only one output type or in only one version of the exam. In that case, you should use the \verb$\mcifoutput$ command: +\begin{code}[commandchars=\!\?\;] +\mcifoutput[!emph?<versions>;]{!emph?<output-types>;}{!emph?<text>;} +\end{code} +This command prints \textit{\texttt{<text>}} in all \textit{\texttt{<output-types>}} given as a comma-separated list. In the \verb$exam$ and \verb$answers$ output types you can also optionally specify the \textit{\texttt{<versions>}} as a comma-separated list. As an example, the code +\begin{code} + \mcifoutput{concept,exam}{name:} +\end{code} +will print ``name:'' on the exams and in the concept version but not on the answers document, the key table, or the analysis document. The command +\begin{code} + \mcifoutput[1,3]{exam}{\newpage} +\end{code} +will start a new page on the exams version 1 and 3 but not in the other versions. If the \textit{\texttt{<versions>}} option is empty, the command will print \textit{\texttt{<text>}} on all versions of the \verb$exam$ documents. Note that the \textit{\texttt{<versions>}} option is ignored for \verb$concept$, \verb$key$ and \verb$analysis$ output. This means that code like +\begin{code} + \mcifoutput[wrong]{exam,concept}{blah} +\end{code} +will print ``blah'' on the concept version because \verb$wrong$ is ignored. However, this code will print nothing on the exams because the \textit{\texttt{<versions>}} option is not empty (although wrong). Note that the optional \textit{\texttt{<versions>}} parameter can not be used in the preamble because the version is only set in stone at the \verb$\begin{document}$. + + + + + + + +\section{Analysis of results\label{sec:analysis}} + + \subsection{Processing with R} + +Typically, multiple choice exams are completed on standard forms which are scanned automatically. The examiner then receives a data file listing all students with their answers. Using this file to grade the students is not an easy task because it firstly requires to map the given permuted answer number to the initial answer number and secondly requires checking whether this answer is right or wrong. The \textsf{mcexam} class allows to do this semi-automatically. + +If the \verb$writeRfile$ package option is enabled, compiling the exam document in any of the output types automatically generates an \verb$R$ file which can be used to process data files with the answers of the students. The \verb$R$ code will be written to the file \verb$\jobname.r$. In case more than one \verb$mcquestions$ environments are present in the document, the second environment will write its \verb$R$-code to the file \verb$\jobname-B.r$, the third will be written to the file \verb$\jobname-C.r$, etc. The \verb$-B$, \verb$-C$, \ldots extensions can be overruled by the optional argument of the \verb$mcquestions$ environment. For example, if you write +\begin{code} +\begin{mcquestions}[myfile] +... +\end{mcquestions} +\end{code} +the \verb$R$-code of this environment will be written to the file \verb$\jobname-myfile.r$. + +In the \verb$R$ file, the function \verb$processanswers$ is defined which processes the answers. This function takes four arguments: +\begin{itemize} + \item \verb$ID$: + A vector with the ID numbers of the students. + \item \verb$version$: + A numeric vector with the version number of the exam for each student in the same order as \verb$ID$. + \item \verb$answers$: + A numeric data frame with the given answers of the students. The columns refer to the questions, the rows to the students in the same order as \verb$ID$. + + Watch out, if your initial data is not numeric, you must first transform the data to numeric answers. For example, if you have a data frame \verb$X$ with answers in capital letters (A-Z) format, you need first to map these letters to the numbers 1-26 by, for example, applying the \verb$match$ function to the data frame: + \begin{quote} + \verb$apply(answers,2,match,LETTERS)$. + \end{quote} + \item \verb$path$: + The path where the function writes information for the analysis output type (see next subsection). By default, the path is the working directory (\verb$getwd()$). +\end{itemize} + +The \verb$processanswers$ function creates a new data frame with the students' ID's, the versions, and two variables for each question. The variables \verb$originalQuestion.x$, where \verb$x$ refers to the question number, store the answers of the students in the initial enlisting of the script file (before permutations). The variables \verb$pointsQuestion.x$ give the points of a student to initial question \verb$x$ (in correct/incorrect mode, it is 1 if a student gave a correct answer to question \verb$x$ and 0 if the student gave a wrong answer). Additionally, there is also the \verb$total$ variable which stores the sum of the points (i.e. the sum of the \verb$pointsQuestion.x$ variables). + +The \verb$processanswers$ function also creates the file \verb$\jobname.ana$ which stores information for the analysis output type. + + + \subsection{Compiling an analysis document} + +After processing the answers in R, you can compile an analysis document with the \verb$output=analysis$ package option. This analysis document includes the percentages of students giving each answer option, the (corrected) p-values, the item-rest correlations, and Cronbach's alpha of the questions. First, confirm that the \verb$\jobname.ana$ file, which was created by R, is in the same folder as your \verb$.tex$ file. In case of multiple \verb$mcquestions$ environments, the program will automatically take the extension into account, also when this is specified by the optional argument of the \verb$mcquestions$ environment. + + + + + + + + + +\section{Lay-out and additional useful commands} + + +\subsection{Tweaking the output types} + +At \verb$\begin{document}$, a set of booleans are defined which depend on the output type and which control how the output is created. These booleans can be changed if you don't like the output of a certain output type. In order to change these booleans, use the +\begin{code}[commandchars=\!\?\;] +\mcsetupConcept{!emph?<keys>;} +\mcsetupExam{!emph?<keys>;} +\mcsetupKey{!emph?<keys>;} +\mcsetupAnswers{!emph?<keys>;} +\mcsetupAnalysis{!emph?<keys>;} +\end{code} +commands, which take a \texttt{key=\textit{value}}-list as argument. The keys which can be used are the following: +\begin{itemize} +\item \verb$showPerVersion=$\emph{true/false}: + If true, only one version is send to the output depending on the \verb$version$ option of the package. If false, a general document is made which summarizes all versions and which may show permutation tables for the questions and answers (if these are permuted at least). +\item \verb$showQuestionPermutationtable=$\emph{true/false}: + Show a permutation table of the questions at the start of the \verb$mcquestions$ environment? +\item \verb$showQuestionsAnalysis=$\emph{true/false}: + Show a the analysis of the questions at the start of the \verb$mcquestions$ environment? (Requires an \verb$.ana$ file). +\item \verb$showQuestionList=$\emph{true/false}: + Show the questions? +\item \verb$showCorrectAnswers=$\emph{true/false}: + Show the correct answers in correct/incorrect-mode? +\item \verb$showAnswerPoints=$\emph{true/false}: + Show the answer points in points-mode? +\item \verb$showExplanation=$\emph{true/false}: + Show the explanation of the correct answer? +\item \verb$showAnswerPermutationTable=$\emph{true/false}: + Show the premutation table of the answers for each question? +\item \verb$showAnswersAnalysis=$\emph{true/false}: + Show a the analysis of the answers for each question? (Requires an \verb$.ana$ file). +\item \verb$showNotes=$\emph{true/false}: + Show the notes for each question? +\item \verb$showKeytable=$\emph{true/false}: + Show the key table? Note that the key table always summarizes all versions. It make no sense to set \verb$showKeytable=true$ if \verb$showPerVersion=true$. +\end{itemize} +As an example, if you don't like the standard way of making a document for each version separately with the answers, you can add the following command to the preamble: +\begin{code}[commandchars=\!\?\;] +\mcsetupAnswers{showPerVersion=false + ,showQuestionPermutationtable=true + ,showAnswerPermutationTable=true + } +\end{code} + + + + + +\subsection{Changing the appearance of the counters}\label{section:counterformats} + +By default, the number format of the version numbers is \verb$\Roman$, of the questions numbers is \verb$\arabic$, and of the answers numbers is \verb$\alph$. These formats can be changed by redefining the \verb$\mcversionlabelfmt$, the \verb$\mcquestionlabelfmt$ and the \verb$\mcanswerlabelfmt$ commands with \verb$\renewcommand$. Currently, these commands are defined as +\begin{code} +\newcommand\mcversionlabelfmt[1]{\Roman{#1}} +\newcommand\mcquestionlabelfmt[1]{\arabic{#1}} +\newcommand\mcanswerlabelfmt[1]{(\alph{#1})} +\end{code} + + + + + + +\subsection{Changing the appearance of the list structures} + +The questions, the answers in the \verb$mcanswerslist$ environment and the question information in the \verb$concept$, \verb$answers$ and \verb$analysis$ output styles are put in newly defined lists using the \verb$enumitem$ package. The lists are \verb$setmcquestions$, \verb$setmcanswerslist$ and \verb$setmcquestioninfo$. You can change the appearance of these lists using the \verb$\setlist$ command from the \verb$enumitem$ package. For more information, refer to the \verb$enumitem$ package documentation. Currently, the lists are defined as +\begin{code} +\setlist[setmcquestions]{label=\mcquestionlabelfmt{*}. + ,ref=\mcquestionlabelfmt{*} + ,itemsep=2\baselineskip + ,topsep=2\baselineskip } +\setlist[setmcanswerslist]{label=\mcanswerlabelfmt{*} + ,noitemsep} +\setlist[setmcquestioninfo]{before=\footnotesize\sffamily} +\end{code} + + + + + + + + + + +\subsection{Changing the appearance of different document elements} + +The package defines several environments which typeset particular content. The \verb$setmcquestioninstruction$ environment typesets the question instructions, the \verb$setmcquestion$ typesets the question and its answer options, the \verb$setmcanswers$ environment typesets the content of the \verb$mcanswers$ environment, the \verb$setmcquestionpermutationtable$ typesets the permutation table of the questions, the \verb$setmcanswerpermutationtable$ typesets the permutation table of the answers, the \verb$setmcquestionanalysistable$ and \verb$setmcansweranalysistable$ environments typeset the analysis tables in the \verb$analysis$ output, and the \verb$setmckeytable$ typesets the key table in the \verb$key$ output. All these environments can be redefined with the \verb$renewenvironment$ command. Currently, they are defined as +\begin{code} +\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}} +\end{code} + +For example, if you want to keep all questions and answer options together on the same page, you can include them in a minipage as follows: +\begin{code} +\renewenvironment{setmcquestion} + {\begin{minipage}[t]{\linewidth-\labelwidth}} + {\end{minipage}\par} +\end{code} +provided that the \verb$calc$ package has been loaded. + + + + + + + + +\subsection{Babel} + +The \verb$babel$ package can be used in an \verb$mcexam$ document. At the moment, a Dutch implemenation is included. For Dutch exams, you include +\begin{code} +\usepackage[dutch]{babel} +\end{code} +in the preamble of your script file. + + + + + + + + + +\end{document} diff --git a/Master/texmf-dist/doc/latex/mcexam/mcexam_example.tex b/Master/texmf-dist/doc/latex/mcexam/mcexam_example.tex new file mode 100644 index 00000000000..64b4c3a9176 --- /dev/null +++ b/Master/texmf-dist/doc/latex/mcexam/mcexam_example.tex @@ -0,0 +1,319 @@ +%%% 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. + + +\documentclass[a4paper]{article} + +\usepackage[output=exam + ,numberofversions=4 + ,version=3 + ,seed=1 + ,randomizequestions=true + ,randomizeanswers=true + ,writeRfile=true + ]{mcexam} + +% Packages used for special things +\usepackage{tikz,framed} + +% Set headers and footers +\usepackage{fancyhdr,lastpage} +\pagestyle{fancy} +\fancyhf{} +\renewcommand{\headrulewidth}{0pt} +\renewcommand{\footrulewidth}{1pt} +\lfoot{\mctheversion} +\rfoot{Page \thepage\ of \pageref{LastPage}} + +% Ensure each question+answers is printed entirely on the same page. +\usepackage{calc} +\renewenvironment{setmcquestion}{\begin{minipage}[t]{\linewidth-\labelwidth}}{\end{minipage}\par} + + + + + + + + +\begin{document} + + + + + + +\begin{center} + \bfseries\LARGE Example Exam \texttt{mcexam} Package +\end{center} + +\begin{framed} + \centering\bfseries\Large\MakeUppercase{\mctheversion} +\end{framed} + +\mcifoutput{concept,exam}{ + + \bigskip + + \noindent Name: \dotfill\\[.5\baselineskip] + \noindent Student Number: \dotfill\\[.5\baselineskip] + \noindent Program: \dotfill + + \vspace{2\baselineskip} + + \noindent\textbf{Instructions:} + \begin{itemize}[nosep] + \item Answer all questions. + \item Fill in the answers on the answer sheet. + \end{itemize} + + } + + + + + +\begin{mcquestions} + + + +\begin{mcquestioninstruction} +The next question is about the sky. +\end{mcquestioninstruction} + +\question What is the color of the sky? + + \begin{mcanswerslist}[fixlast] + \answer[correct] blue + \answer green + \answer red + \answer yellow + \answer none of the above + \end{mcanswerslist} + + \begin{mcexplanation} + If you look up to the sky and there are no clouds, you'll see it is blue. + \end{mcexplanation} + + \begin{mcnotes} + This question had a large proportion of good answers last year. + \end{mcnotes} + + + + +\question Which figure is a square? + \begin{mcanswers} + \begin{tabular}{@{}cccc} + \answer{1}{\tikz{\draw (-0.66,0)--(0.66,0)--(0,1)--cycle;}}& + \answer{2}{\tikz{\draw (0,0)--(2,0)--(2,1)--(0,1)--cycle;}}& + \answer[correct]{3}{\tikz{\draw (0,0)--(1,0)--(1,1)--(0,1)--cycle;}}& + \answer{4}{\tikz{\draw (0,0) circle[radius=0.5];}}\\ + \answernum{1}&\answernum{2}&\answernum{3}&\answernum{4}\\ + \end{tabular} + \end{mcanswers} + + + + + +\begin{mcquestioninstruction} +Questions \ref{ref1} to \ref{ref2} are about maths. +\end{mcquestioninstruction} + +\question What is the value of $\pi$?\label{ref1} + + \begin{mcanswerslist}[{1,2,3,4},{2,3,4,1},{3,4,1,2}] + \answer[correct] 3.14 + \answer 2.19 + \answer a billion + \answer 0 + \end{mcanswerslist} + + \begin{mcexplanation} + $\pi$ is 3.14 + \end{mcexplanation} + +\question[follow] How much is 2 + 2 ? + + \begin{mcanswerslist}[ordinal] + \answer 3 + \answer[correct] 4 + \answer 5 + \answer 6 + \answer 7 + \end{mcanswerslist} + + +\question[follow] The square root of 2 is \ldots\label{ref2} + + \begin{mcanswerslist}[fixlast] + \answer 2.1 + \answer[correct] smaller than 2 + \answer larger than a billion + \answer none of the above + \end{mcanswerslist} + + + +\question Which statement is correct? + + \begin{mcanswerslist}[{1,2,3,4},{2,1,4,3},{3,4,1,2},{4,3,2,1}] + \answer The moon is a planet. + \answer The moon is a star. + \answer The sun is a planet. + \answer[correct] The sun is a star. + \end{mcanswerslist} + +\question Which is the letter alpha? + + \begin{mcanswers} + \begin{tabular}{cccc} + \answer[correct]{1}{\Huge$\alpha$} & + \answer{2}{\Huge$\beta$} & + \answer{3}{\Huge$\gamma$} & + \answer{4}{\Huge$\delta$} \\[0.1\baselineskip] + \answernum{1}&\answernum{2}&\answernum{3}&\answernum{4}\\ + \end{tabular} + \end{mcanswers} + + + + + +\question What year did Albert Einstein die? + + \begin{mcanswerslist}[ordinal] + \answer 1949 + \answer 1954 + \answer[correct] 1955 + \answer 1960 + \end{mcanswerslist} + + + +\question Which is the largest planet in the solar system? + + \begin{mcanswerslist} + \answer[correct] Jupiter + \answer Neptune + \answer Earth + \answer Mars + \end{mcanswerslist} + + +\question What colour is Cerulean? + + \begin{mcanswerslist} + \answer Red + \answer[correct] Blue + \answer Yellow + \answer Green + \end{mcanswerslist} + +\question What are a group of Dolphins called? + + \begin{mcanswerslist} + \answer School + \answer Herd + \answer[correct] Pod + \answer Pool + \end{mcanswerslist} + +\question Who invented Penicillin? + + \begin{mcanswerslist} + \answer[correct] Alexandra Fleming + \answer Thomas Edison + \answer Marie Curie + \answer George Orwell + \end{mcanswerslist} + +\question What date was President John F Kennedy assassinated? + + \begin{mcanswerslist}[{1,2,3,4},{1,3,2,4},{4,3,2,1},{4,2,3,1}] + \answer November 22 1962 + \answer November 24 1962 + \answer[correct] November 22 1963 + \answer November 24 1963 + + \end{mcanswerslist} + +\question How many men have walked on the moon? + + \begin{mcanswerslist}[ordinal] + \answer 5 + \answer 9 + \answer 10 + \answer[correct] 12 + \end{mcanswerslist} + +\question Who has won the most Academy Awards? + + \begin{mcanswerslist} + \answer James Cameron + \answer[correct] Walt Disney + \answer Katherine Hepburn + \answer Steven Spielberg + \end{mcanswerslist} + +\question What is the currency of Brazil? + + \begin{mcanswerslist}[{1,2,3,4},{2,1,3,4}] + \answer Dollar + \answer[correct] Real + \answer Dollar \emph{and} Real + \answer None of the above + \end{mcanswerslist} + + + + + +\question Is this the last question? it is a very long question which spans several lines of the document. + + \begin{mcanswerslist}[permutenone] + \answer[correct] yes + \answer no + \end{mcanswerslist} + + \begin{mcexplanation} + It may not be the last question in your exam, but it is the question which was last programmed. + \end{mcexplanation} + + +\end{mcquestions} + + + + + +\mcifoutput{concept,exam}{ + + \vspace{2\baselineskip} + + \noindent\textbf{Instructions:} + \begin{itemize}[nosep] + \item You finished the exam! + \item Hand in the answer sheet. + \end{itemize} + + } + + + + + + + + + +\end{document} diff --git a/Master/texmf-dist/doc/latex/mcexam/mcexam_example_dataset.r b/Master/texmf-dist/doc/latex/mcexam/mcexam_example_dataset.r new file mode 100644 index 00000000000..9fa54e062da --- /dev/null +++ b/Master/texmf-dist/doc/latex/mcexam/mcexam_example_dataset.r @@ -0,0 +1,42 @@ +### mcexam_example_dataset.r +### This code contains some test data for the example of mcexam. First run +### mcexam_example.tex through LaTeX, then process this file with R. Next, +### you can make an analysis version of the exam in LaTeX. Make sure the +### working directory is the folder where mcexam_example.tex resorts. +### +### 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. + +rm(list = ls()) + +ID <- c(1,2,3,4,5,6,7,8,9,10) +versions <- c(1,1,1,2,2,2,2,3,3,3) +answers <- rbind(c(1,2,1,4,2, 3,4,3,1,1, 2,2,2,5,2, 1,3) #17 + ,c(1,1,2,4,3, 2,2,3,1,2, 2,3,2,5,2, 2,3) #9 + ,c(1,2,1,3,2, 3,4,2,1,1, 2,2,3,5,1, 1,3) #8 + ,c(3,2,5,4,2, 4,1,3,4,1, 2,3,1,1,2, 2,3) #11 + ,c(2,2,5,3,2, 3,1,2,4,2, 2,3,1,1,1, 2,3) #0 + ,c(3,2,5,4,2, 4,1,3,3,1, 2,2,1,1,2, 1,4) #7 + ,c(3,2,5,4,2, 3,1,3,4,2, 2,3,2,1,1, 2,1) #2 + ,c(2,1,4,2,1, 1,3,5,4,1, 1,3,1,4,3, 2,4) #6 + ,c(2,1,3,3,1, 1,3,5,4,1, 1,2,1,4,3, 2,4) #11 + ,c(1,1,3,3,2, 1,2,5,4,3, 2,3,4,3,3, 1,3) #4 + ) + +source("mcexam_example.r") +data <- mcprocessanswers(ID,versions,answers) + + + + + + +
\ No newline at end of file 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<mcexam.sty> + + +%%%% 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("(?<![0-9.])0+","", sprintf("\@percentchar .3f",x),perl = TRUE) } + \addtostream{@Rfile}{ n <- nchar(y) } + \addtostream{@Rfile}{ y <- gsub(" ","\\\\phantom\@lbracesign -\@rbracesign ",y) } + \addtostream{@Rfile}{ y <- paste0(strrep("\\phantom\@lbracesign 0\@rbracesign ",max(n)-n),y) } + \addtostream{@Rfile}{ y } + \addtostream{@Rfile}{ \@rbracesign ; } + \addtostream{@Rfile}{write(c( } + \addtostream{@Rfile}{ "\\gdef\\mc@questionAnalysisTable\@lbracesign ", } + \addtostream{@Rfile}{ " \\begin\@lbracesign setmcquestionanalysistable\@rbracesign ", } + \ifbool{mc@correct}{ + \addtostream{@Rfile}{ " \\begin\@lbracesign longtable\@rbracesign \@lbracesign cccc\@rbracesign ", } + \addtostream{@Rfile}{ " & \\mc@babel@Proportion & \\mc@babel@Corrected & \\mc@babel@Item@rest \\\\", } + \addtostream{@Rfile}{ " & \\mc@babel@correct & \\mc@babel@proportion & \\mc@babel@correlation \\\\", } + \addtostream{@Rfile}{ " \\hline", } + \addtostream{@Rfile}{ " \\mc@babel@Question \\\\", } + \addtostream{@Rfile}{ " \\endhead", } + \addtostream{@Rfile}{ " \\hline", } + \addtostream{@Rfile}{ " \\endfoot", } + \addtostream{@Rfile}{ " \\hline", } + \addtostream{@Rfile}{ paste0(" \\multicolumn\@lbracesign 4\@rbracesign \@lbracesign l\@rbracesign \@lbracesign \\mc@babel@Number@of@students\\ = ",Nstudents,"\@rbracesign \\\\"), } + \addtostream{@Rfile}{ paste0(" \\multicolumn\@lbracesign 4\@rbracesign \@lbracesign l\@rbracesign \@lbracesign Cronbach's alpha = ",sprintf("\@percentchar .3f",alpha),"\@rbracesign \\\\"), } + \addtostream{@Rfile}{ " \\endlastfoot ", } + \addtostream{@Rfile}{ paste0(" \\setcounter\@lbracesign mc@counter\@rbracesign \@lbracesign ",1:ncol(answers),"\@rbracesign \\mcquestionlabelfmt\@lbracesign mc@counter\@rbracesign & " } + \addtostream{@Rfile}{ ,formatnumber(p)," & ",formatnumber(p.cor)," & ",formatnumber(r.cor)," \\\\"), } + \addtostream{@Rfile}{ " \\end\@lbracesign longtable\@rbracesign ", } + }{} + \ifbool{mc@points}{ + \addtostream{@Rfile}{ " \\begin\@lbracesign longtable\@rbracesign \@lbracesign ccc\@rbracesign ", } + \addtostream{@Rfile}{ " & & \\mc@babel@Item@rest \\\\", } + \addtostream{@Rfile}{ " & \\mc@babel@Mean & \\mc@babel@correlation \\\\", } + \addtostream{@Rfile}{ " \\hline", } + \addtostream{@Rfile}{ " \\mc@babel@Question \\\\", } + \addtostream{@Rfile}{ " \\endhead", } + \addtostream{@Rfile}{ " \\hline", } + \addtostream{@Rfile}{ " \\endfoot", } + \addtostream{@Rfile}{ " \\hline", } + \addtostream{@Rfile}{ paste0(" \\multicolumn\@lbracesign 3\@rbracesign \@lbracesign l\@rbracesign \@lbracesign \\mc@babel@Number@of@students\\ = ",Nstudents,"\@rbracesign \\\\"), } + \addtostream{@Rfile}{ paste0(" \\multicolumn\@lbracesign 3\@rbracesign \@lbracesign l\@rbracesign \@lbracesign Cronbach's alpha = ",sprintf("\@percentchar .3f",alpha),"\@rbracesign \\\\"), } + \addtostream{@Rfile}{ " \\endlastfoot ", } + \addtostream{@Rfile}{ paste0(" \\setcounter\@lbracesign mc@counter\@rbracesign \@lbracesign ",1:ncol(answers),"\@rbracesign \\mcquestionlabelfmt\@lbracesign mc@counter\@rbracesign & " } + \addtostream{@Rfile}{ ,formatnumber(p)," & ",formatnumber(r.cor)," \\\\"), } + \addtostream{@Rfile}{ " \\end\@lbracesign longtable\@rbracesign ", } + }{} + \addtostream{@Rfile}{ " \\end\@lbracesign setmcquestionanalysistable\@rbracesign ", } + \addtostream{@Rfile}{ " \@rbracesign " } + \addtostream{@Rfile}{ ),outputfilename,append=TRUE) ; } + \addtostream{@Rfile}{ } + %%% Write answer analysis tables + \addtostream{@Rfile}{versions.factor <- factor(versions); } + \addtostream{@Rfile}{levels(versions.factor) <- 1:Nversions; } + \addtostream{@Rfile}{for (i in 1:Nquestions) \@lbracesign } + \addtostream{@Rfile}{ X <- factor(Q[,i],1:Nanswers[i]); } + \addtostream{@Rfile}{ props <- cbind(prop.table(table(X,versions.factor,useNA="ifany"),2),prop.table(table(X,useNA="ifany"))); } + \addtostream{@Rfile}{ dims <- dim(props); } + \addtostream{@Rfile}{ props <- lapply(props,function(x) ifelse(is.na(x),"N.A.",gsub(" ","\\\\phantom\@lbracesign 0\@rbracesign ",paste0(sprintf("\@percentchar 5.1f",x*100),"\\\@percentchar ")))); } + \addtostream{@Rfile}{ dim(props) <- dims; } + \addtostream{@Rfile}{ props <- apply(props, 1, paste, collapse=" & "); } + \addtostream{@Rfile}{ labels <- paste0(" \\setcounter\@lbracesign mc@counter\@rbracesign \@lbracesign ",1:Nanswers[i],"\@rbracesign \\mcanswerlabelfmt\@lbracesign mc@counter\@rbracesign "); } + \addtostream{@Rfile}{ labels <- ifelse(is.na(labels[1:dims[1]])," invalid",labels[1:dims[1]]) } + \addtostream{@Rfile}{write(c( } + \addtostream{@Rfile}{ paste0("\\csgdef\@lbracesign mc@answerAnalysisTable",i,"\@rbracesign \@lbracesign "), } + \addtostream{@Rfile}{ paste0(" \\begin\@lbracesign tabular\@rbracesign \@lbracesign c",strrep("c",Nversions),"c\@rbracesign "), } + \addtostream{@Rfile}{ paste0(" \\multicolumn\@lbracesign 1\@rbracesign \@lbracesign r\@rbracesign \@lbracesign \\mc@babel@Version\@rbracesign &" } + \addtostream{@Rfile}{ ,paste(paste0("\\setcounter\@lbracesign mc@counter\@rbracesign \@lbracesign ",1:Nversions, } + \addtostream{@Rfile}{ "\@rbracesign \\mcversionlabelfmt\@lbracesign mc@counter\@rbracesign "),collapse="&") } + \addtostream{@Rfile}{ ," & \\mc@babel@total \\\\"), } + \addtostream{@Rfile}{ " \\hline", } + \addtostream{@Rfile}{ " \\mc@babel@Answer \\\\", } + \addtostream{@Rfile}{ paste0(labels," & ",props,"\\\\"), } + \addtostream{@Rfile}{ " \\hline", } + \ifbool{mc@correct}{ + \addtostream{@Rfile}{ paste0(" \\multicolumn\@lbracesign ",Nversions+2,"\@rbracesign \@lbracesign l\@rbracesign \@lbracesign \\mc@babel@Proportion@correct\\ = ", } + \addtostream{@Rfile}{ sprintf("\@percentchar .3f",p[i]),"\@rbracesign \\\\"), } + \addtostream{@Rfile}{ paste0(" \\multicolumn\@lbracesign ",Nversions+2,"\@rbracesign \@lbracesign l\@rbracesign \@lbracesign \\mc@babel@Corrected@proportion\\ = ", } + \addtostream{@Rfile}{ sprintf("\@percentchar .3f",p.cor[i]),"\@rbracesign \\\\"), } + }{} + \ifbool{mc@points}{ + \addtostream{@Rfile}{ paste0(" \\multicolumn\@lbracesign ",Nversions+2,"\@rbracesign \@lbracesign l\@rbracesign \@lbracesign \\mc@babel@Mean\\ = ", } + \addtostream{@Rfile}{ sprintf("\@percentchar .3f",p[i]),"\@rbracesign \\\\"), } + }{} + \addtostream{@Rfile}{ paste0(" \\multicolumn\@lbracesign ",Nversions+2,"\@rbracesign \@lbracesign l\@rbracesign \@lbracesign \\mc@babel@Item@rest@correlation\\ = ", } + \addtostream{@Rfile}{ sprintf("\@percentchar .3f",r.cor[i]),"\@rbracesign \\\\"), } + \addtostream{@Rfile}{ " \\end\@lbracesign tabular\@rbracesign ", } + \addtostream{@Rfile}{ " \@rbracesign " } + \addtostream{@Rfile}{ ),outputfilename,append=TRUE) ; } + \addtostream{@Rfile}{ \@rbracesign } + \addtostream{@Rfile}{ } + %%% Close output file .ana + \addtostream{@Rfile}{write("\\makeatother",outputfilename,append=TRUE) ; } + \addtostream{@Rfile}{ } + %%% Output the data + \addtostream{@Rfile}{outputdata ; } + %%% Close the output file + \addtostream{@Rfile}{ \@rbracesign } + \closeoutputstream{@Rfile} + %%% Read the .ana file + \ifbool{mc@analysis}{ + \IfFileExists{\jobname\mc@themcquestions.ana}% + {\@input{\jobname\mc@themcquestions.ana}} + {\PackageError{mcexam}{File \jobname\mc@themcquestions.ana not present}{Run the R code or ensure the \jobname\mc@themcquestions.ana is in the correct folder.}} + }{} + }{} + } + + + + + + + + + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% 5. TYPESET CONTENT +%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\def\mc@typesetContent{ + \ifbool{mc@showQuestionPermutationtable}{\mc@questionPermutationtable}{} %%% Subsection 5.1 + \ifbool{mc@showQuestionsAnalysis}{\mc@generalAnalysisInfo}{} %%% Subsection 5.2 + \ifbool{mc@showQuestionList}{\mc@questionList}{} %%% Subsection 5.3 + \ifbool{mc@showKeytable}{\mc@keytable}{} %%% Subsection 5.4 + } + + + + + + + + +%%% 4.1 Question Permutation Table +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\def\mc@questionPermutationtable{ + \ifbool{mc@randomizeQuestions}{ + \gdef\mc@temp{} + \numdef\mc@numcol{\mc@totalNumberOfVersions+2} + \gappto\mc@temp{\begin{longtable}{cc*{\mc@totalNumberOfVersions}{c}}} + \xappto\mc@temp{\noexpand\multicolumn{\mc@numcol}{@{}l}{\noexpand\textbf{\mc@babel@Question@permutation@table:}}\noexpand\\} + \gappto\mc@temp{\multicolumn{2}{r}{\mc@babel@Version}} + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \setcounter{mc@counter}{\v} + \xappto\mc@temp{&\mcversionlabelfmt{mc@counter}} + } + \gappto\mc@temp{\\} + \gappto\mc@temp{ \hline } + \gappto\mc@temp{ \endhead } + \gappto\mc@temp{ \hline } + \xappto\mc@temp{\noexpand\multicolumn{\mc@numcol}{@{}l}{*: \mc@babel@Question@follows@previous}\noexpand\\} + \gappto\mc@temp{ \endfoot } + \gappto\mc@temp{ \mc@babel@Question \\ } + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \setcounter{mc@counter}{\q} + \xappto\mc@temp{\mcquestionlabelfmt{mc@counter}} + \ifcsstring{mc@questionOption\q}{follow}{ + \ifnumequal{\q}{1}{}{ + \gappto\mc@temp{\makebox[0pt][l]{*}} + }}{} + \gappto\mc@temp{& $\rightarrow$ } + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \setcounter{mc@counter}{\csuse{mc@randomQuestionNumberV\v Q\q}} + \xappto\mc@temp{ &\mcquestionlabelfmt{mc@counter}} + } + \gappto\mc@temp{\\} + } + \gappto\mc@temp{\end{longtable}} + \begin{setmcquestionpermutationtable} + \mc@temp + \end{setmcquestionpermutationtable} + }{} + } + + + + + + + +%%% 4.2 General Analysis Info +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\gdef\mc@generalAnalysisInfo{ + \mc@questionAnalysisTable + } + + + + + + + + + + + + +%%% 4.3 Question list +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\def\mc@questionList{ + \mc@questionList@setmcanswerslist + \mc@questionList@setmcanswers + %%% + \gdef\mc@questionList@enumerate{} + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + % Set \theq the question number to be printed. + \ifbool{mc@showPerVersion}{ + \xappto\mc@questionList@enumerate{\noexpand\xdef\noexpand\theq{\csuse{mc@originalQuestionNumberV\mc@theVersion Q\q}}} + }{ + \xappto\mc@questionList@enumerate{\noexpand\xdef\noexpand\theq{\q}} + } + % Print the question instruction. + \ifnumequal{\q}{1}{ + \gappto\mc@questionList@enumerate{ + \ifcsempty{mc@questionInstruction\theq}{}{ + \begin{setmcquestioninstruction} + \csuse{mc@questionInstruction\theq} + \end{setmcquestioninstruction} + } + } + }{ + \gappto\mc@questionList@enumerate{ + \ifcsempty{mc@questionInstruction\theq}{}{ + \end{setmcquestions} + \begin{setmcquestioninstruction} + \csuse{mc@questionInstruction\theq} + \end{setmcquestioninstruction} + \begin{setmcquestions}[resume] + } + } + } + % At the first question, open the list environment. + \ifnumequal{\q}{1}{\gappto\mc@questionList@enumerate{\begin{setmcquestions}}}{} + % Add the question. + \gappto\mc@questionList@enumerate{\item \begin{setmcquestion}\csuse{mc@question\theq}\end{setmcquestion}} + % Add question info + \gappto\mc@questionList@enumerate{\mc@questionList@questionInfo} + } + % Close the list environment after the last question. + \gappto\mc@questionList@enumerate{\end{setmcquestions}} + %%% + {\@beginparpenalty=10000 \mc@questionList@enumerate} + } + + + + + +\def\mc@questionList@setmcanswerslist{ + \RenewEnviron{mcanswerslist}[1][]{ + \gdef\mc@answerslist@enumerate{} + \gappto\mc@answerslist@enumerate{\begin{setmcanswerslist}} + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\theq}}{ + \ifbool{mc@showPerVersion}{ + \xappto\mc@answerslist@enumerate{\noexpand\xdef\noexpand\thea{\csuse{mc@originalAnswerNumberV\mc@theVersion Q\theq A\a}}} + }{ + \xappto\mc@answerslist@enumerate{\noexpand\xdef\noexpand\thea{\a}} + } + \gappto\mc@answerslist@enumerate{\item \csuse{mc@answerQ\theq A\thea}} + } + \gappto\mc@answerslist@enumerate{\end{setmcanswerslist}} + \mc@answerslist@enumerate + } + } + + + +\def\mc@questionList@setmcanswers{ + \RenewEnviron{mcanswers}[1][]{ + \providecommand\answer[3][]{} + \renewcommand\answer[3][]{% + \ifbool{mc@showPerVersion}{\xdef\thea{\csuse{mc@originalAnswerNumberV\mc@theVersion Q\theq A####2}}}{\xdef\thea{####2}}% + \csuse{mc@answerQ\theq A\thea}% + } + \providecommand\answernum[1]{} + \renewcommand\answernum[1]{\setcounter{mc@counter}{####1}\mcanswerlabelfmt{mc@counter}} + \par\begin{setmcanswers}\BODY\end{setmcanswers} + } + } + + + +\def\mc@questionList@questionInfo{ + \gdef\mc@questionInfoBODY{} + % Add the correct answer. + \ifboolexpr{bool{mc@correct} and bool{mc@showCorrectAnswers} and test{\ifnumgreater{\csuse{mc@totalNumberOfAnswersQ\theq}}{0}}}{ + \gappto\mc@questionInfoBODY{\item[\mc@babel@Correct@answers:]} + \xdef\mc@temp{0} + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\theq}}{ + \ifbool{mc@showPerVersion}{ + \xdef\thea{\csuse{mc@originalAnswerNumberV\mc@theVersion Q\theq A\a}} + }{ + \xdef\thea{\a} + } + \ifcsstring{mc@answerOptionQ\theq A\thea}{correct}{ + \ifdefstring{\mc@temp}{0}{ + \xappto\mc@questionInfoBODY{\noexpand\setcounter{mc@counter}{\a}} + \gappto\mc@questionInfoBODY{\mcanswerlabelfmt{mc@counter}} + \xdef\mc@temp{1} + }{ + \xappto\mc@questionInfoBODY{\noexpand\setcounter{mc@counter}{\a}} + \gappto\mc@questionInfoBODY{, \mcanswerlabelfmt{mc@counter}} + } + }{} + } + }{} + % Add the answer points + \ifboolexpr{bool{mc@points} and bool{mc@showAnswerPoints}}{ + \gappto\mc@questionInfoBODY{\item[\mc@babel@Answer@points:] } + \xdef\mc@temp{0} + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\theq}}{ + \ifbool{mc@showPerVersion}{ + \xdef\thea{\csuse{mc@originalAnswerNumberV\mc@theVersion Q\theq A\a}} + }{ + \xdef\thea{\a} + } + \ifdefstring{\mc@temp}{1}{ + \gappto\mc@questionInfoBODY{, } + }{ + \xdef\mc@temp{1} + } + \xappto\mc@questionInfoBODY{\noexpand\setcounter{mc@counter}{\a}} + \gappto\mc@questionInfoBODY{\mcanswerlabelfmt{mc@counter} = } + \ifcsstring{mc@answerOptionQ\theq A\thea}{correct}{ + \gappto\mc@questionInfoBODY{1 \mc@babel@point} + }{ + \ifcsstring{mc@answerOptionQ\theq A\thea}{1}{ + \gappto\mc@questionInfoBODY{1 \mc@babel@point} + }{ + \ifcsstring{mc@answerOptionQ\theq A\thea}{-1}{ + \gappto\mc@questionInfoBODY{-1 \mc@babel@point} + }{ + \IfDecimal{\csuse{mc@answerOptionQ\theq A\thea}}{ + \xappto\mc@questionInfoBODY{\csuse{mc@answerOptionQ\theq A\thea} \mc@babel@points} + }{ + \gappto\mc@questionInfoBODY{0 \mc@babel@points} + }}}} + } + }{} + % Add the exlanation + \ifbool{mc@showExplanation}{ + \ifcsdef{mc@questionExplanationQ\theq}{ + \gappto\mc@questionInfoBODY{\item[\mc@babel@Explanation:] \csuse{mc@questionExplanationQ\theq}} + }{} + }{} + % Add the answer permutation table + \ifboolexpr{ bool{mc@randomizeAnswers} and bool{mc@showAnswerPermutationTable} and test{\ifnumgreater{\csuse{mc@totalNumberOfAnswersQ\theq}}{0}}}{ + \gappto\mc@questionInfoBODY{\item[\mc@babel@Answer@permutations:]} + \ifcsempty{mc@answerPermuteTypeQ\theq}{\gappto\mc@questionInfoBODY{(\mc@babel@All@answers@permuted)}}{ + \ifcsstring{mc@answerPermuteTypeQ\theq}{permuteall}{\gappto\mc@questionInfoBODY{(\mc@babel@All@answers@permuted)}}{ + \ifcsstring{mc@answerPermuteTypeQ\theq}{fixlast}{\gappto\mc@questionInfoBODY{(\mc@babel@All@answers@permuted@except@last@answer)}}{ + \ifcsstring{mc@answerPermuteTypeQ\theq}{ordinal}{\gappto\mc@questionInfoBODY{(\mc@babel@Order@of@answers@permuted)}}{ + \ifcsstring{mc@answerPermuteTypeQ\theq}{permutenone}{\gappto\mc@questionInfoBODY{(\mc@babel@No@answers@permuted)}}{ + \gappto\mc@questionInfoBODY{(\mc@babel@Answers@permuted@by@user)}}}}}} + \gappto\mc@questionInfoBODY{\par\nobreak\@afterheading} + \gappto\mc@questionInfoBODY{\begin{setmcanswerpermutationtable}\begin{tabular}{cc*{\mc@totalNumberOfVersions}{c}}} + \gappto\mc@questionInfoBODY{\multicolumn{2}{r}{\mc@babel@Version}} + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \setcounter{mc@counter}{\v} + \xappto\mc@questionInfoBODY{& \mcversionlabelfmt{mc@counter}} + } + \gappto\mc@questionInfoBODY{ \\ } + \gappto\mc@questionInfoBODY{ \hline } + \gappto\mc@questionInfoBODY{ \mc@babel@Answer \\ } + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\theq}}{ + \setcounter{mc@counter}{\a} + \xappto\mc@questionInfoBODY{\mcanswerlabelfmt{mc@counter}} + \gappto\mc@questionInfoBODY{& $\rightarrow$ } + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \setcounter{mc@counter}{\csuse{mc@randomAnswerNumberV\v Q\theq A\a}} + \xappto\mc@questionInfoBODY{ &\mcanswerlabelfmt{mc@counter}} + } + \gappto\mc@questionInfoBODY{\\} + } + \gappto\mc@questionInfoBODY{\hline} + \gappto\mc@questionInfoBODY{\end{tabular}\end{setmcanswerpermutationtable}} + }{} + % Add the answer analysis + \ifbool{mc@showAnswersAnalysis}{{ + \gappto\mc@questionInfoBODY{\item[\mc@babel@Analysis:]\mbox{}} + \gappto\mc@questionInfoBODY{\par\nobreak\@afterheading} + \gappto\mc@questionInfoBODY{\begin{setmcansweranalysistable}} + \xappto\mc@questionInfoBODY{\noexpand\csuse{mc@answerAnalysisTable\theq}} + \gappto\mc@questionInfoBODY{\end{setmcansweranalysistable}} + }}{} + % Add the notes + \ifbool{mc@showNotes}{ + \ifcsdef{mc@questionNotesQ\theq}{ + \gappto\mc@questionInfoBODY{\item[\mc@babel@Notes:] \csuse{mc@questionNotesQ\theq}} + }{} + }{} + % Output the question Info. + \ifdefempty\mc@questionInfoBODY{}{ + \begin{setmcquestioninfo} + \mc@questionInfoBODY + \end{setmcquestioninfo} + } + } + + + + + + + + + + + + + + + + + + +%%% 4.4 Key Table +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\def\mc@keytable{ + \ifbool{mc@correct}{\mc@correctkeytable}{} + \ifbool{mc@points}{\mc@pointskeytable}{} + } + + +\def\mc@correctkeytable{ + \gdef\mc@keytableBODY{} + \gappto\mc@keytableBODY{\begin{longtable}{c*{\mc@totalNumberOfVersions}{c}}} + \gappto\mc@keytableBODY{\multicolumn{1}{r}{\mc@babel@Version}} + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \setcounter{mc@counter}{\v} + \xappto\mc@keytableBODY{&\mcversionlabelfmt{mc@counter}} + } + \gappto\mc@keytableBODY{ \\ } + \gappto\mc@keytableBODY{ \hline } + \gappto\mc@keytableBODY{\mc@babel@Question \\} + \gappto\mc@keytableBODY{ \endhead } + \gappto\mc@keytableBODY{ \hline } + \gappto\mc@keytableBODY{ \endfoot } + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \setcounter{mc@counter}{\q} + \xappto\mc@keytableBODY{\mcquestionlabelfmt{mc@counter}} + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \gappto\mc@keytableBODY{& } + \xdef\theq{\csuse{mc@originalQuestionNumberV\v Q\q}} + \xdef\mc@temp{0} + \foreach \a in {1,...,\csuse{mc@totalNumberOfAnswersQ\theq}}{ + \xdef\thea{\csuse{mc@originalAnswerNumberV\v Q\theq A\a}}% + \ifcsstring{mc@answerOptionQ\theq A\thea}{correct}{ + \ifdefstring{\mc@temp}{0}{\xdef\mc@temp{1}}{\xappto\mc@keytableBODY{,}} + \setcounter{mc@counter}{\a} + \xappto\mc@keytableBODY{\mcanswerlabelfmt{mc@counter}} + }{} + } + } + \gappto\mc@keytableBODY{\\} + } + \gappto\mc@keytableBODY{\end{longtable}} + \begin{setmckeytable} + \mc@keytableBODY + \end{setmckeytable} + } + + +\def\mc@pointskeytable{ + \gdef\mc@keytableBODY{} + \gappto\mc@keytableBODY{\begin{longtable}{l*{\mc@totalNumberOfVersions}{c}}} + \gappto\mc@keytableBODY{\multicolumn{1}{r}{\mc@babel@Version}} + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \setcounter{mc@counter}{\v} + \xappto\mc@keytableBODY{&\mcversionlabelfmt{mc@counter}} + } + \gappto\mc@keytableBODY{ \\ } + \gappto\mc@keytableBODY{ \hline } + \gappto\mc@keytableBODY{ \endhead } + \gappto\mc@keytableBODY{ \hline } + \gappto\mc@keytableBODY{ \endfoot } + \foreach \q in {1,...,\mc@totalNumberOfQuestions}{ + \setcounter{mc@counter}{\q} + \xappto\mc@keytableBODY{\mc@babel@Question\ \mcquestionlabelfmt{mc@counter}} + \gappto\mc@keytableBODY{\\} + \xdef\mc@maxNumberOfAnswers{1} + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \xdef\theq{\csuse{mc@originalQuestionNumberV\v Q\q}} + \ifnumgreater{\csuse{mc@totalNumberOfAnswersQ\theq}}{\mc@maxNumberOfAnswers}{ + \xdef\mc@maxNumberOfAnswers{\csuse{mc@totalNumberOfAnswersQ\theq}} + }{} + } + \foreach \a in {1,...,\mc@maxNumberOfAnswers}{ + \setcounter{mc@counter}{\a} + \xappto\mc@keytableBODY{\quad\mc@babel@Answer\ \mcanswerlabelfmt{mc@counter}:} + \foreach \v in {1,...,\mc@totalNumberOfVersions}{ + \xdef\theq{\csuse{mc@originalQuestionNumberV\v Q\q}} + \xdef\thea{\csuse{mc@originalAnswerNumberV\v Q\theq A\a}} + \ifnumgreater{\a}{\csuse{mc@totalNumberOfAnswersQ\theq}}{ + \gappto\mc@keytableBODY{& ---} + }{ + \ifcsstring{mc@answerOptionQ\theq A\thea}{correct}{ + \gappto\mc@keytableBODY{& 1\,\mc@babel@pt} + }{ + \ifcsstring{mc@answerOptionQ\theq A\thea}{1}{ + \gappto\mc@keytableBODY{& 1\,\mc@babel@pt} + }{ + \ifcsstring{mc@answerOptionQ\theq A\thea}{-1}{ + \gappto\mc@keytableBODY{& -1\,\mc@babel@pt} + }{ + \IfDecimal{\csuse{mc@answerOptionQ\theq A\thea}}{ + \xappto\mc@keytableBODY{& \csuse{mc@answerOptionQ\theq A\thea}\noexpand\,\mc@babel@pts} + }{ + \gappto\mc@keytableBODY{& 0\,\mc@babel@pts} + }}}} + } + } + \gappto\mc@keytableBODY{\\} + } + } + \gappto\mc@keytableBODY{\end{longtable}} + \begin{setmckeytable} + \mc@keytableBODY + \end{setmckeytable} + } + + + + + + + + + + + +\endinput + + + + + + + + diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check index 31a90436fa2..7d1170be691 100755 --- a/Master/tlpkg/bin/tlpkg-ctan-check +++ b/Master/tlpkg/bin/tlpkg-ctan-check @@ -401,7 +401,7 @@ my @TLP_working = qw( mathcomp mathdesign mathdots mathexam mathpartir mathpunctspace mathspec mathtools matlab-prettifier mathspic maths-symbols mattens maybemath mbenotes - mcaption mceinleger mcf2graph mcite mciteplus mcmthesis + mcaption mceinleger mcexam mcf2graph mcite mciteplus mcmthesis mdframed mdputu mdsymbol mdwtools media9 medstarbeamer meetingmins memdesign memexsupp memoir MemoirChapStyles memory mendex-doc mentis diff --git a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc index 670d28705e7..a7e9fafe63b 100644 --- a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc +++ b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc @@ -636,6 +636,7 @@ depend maybemath depend mbenotes depend mcaption depend mceinleger +depend mcexam depend mcite depend mciteplus depend mdframed diff --git a/Master/tlpkg/tlpsrc/mcexam.tlpsrc b/Master/tlpkg/tlpsrc/mcexam.tlpsrc new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/Master/tlpkg/tlpsrc/mcexam.tlpsrc |