summaryrefslogtreecommitdiff
path: root/Master
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2024-01-28 21:25:18 +0000
committerKarl Berry <karl@freefriends.org>2024-01-28 21:25:18 +0000
commite18df888e4bc09406879efa3de9ad2adbac6ad45 (patch)
tree5313b1361f459513762630be1ff732be7623a528 /Master
parent9b52f6425cd55f5efe960c01c2b6dc9526957918 (diff)
randexam (28jan24)
git-svn-id: svn://tug.org/texlive/trunk@69622 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
-rw-r--r--Master/texmf-dist/doc/latex/randexam/randexam-a-answer.pdfbin49561 -> 49496 bytes
-rw-r--r--Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex18
-rw-r--r--Master/texmf-dist/doc/latex/randexam/randexam-a-blank.pdfbin41354 -> 41288 bytes
-rw-r--r--Master/texmf-dist/doc/latex/randexam/randexam-b-answer.pdfbin49564 -> 49469 bytes
-rw-r--r--Master/texmf-dist/doc/latex/randexam/randexam-b-blank.pdfbin41312 -> 41229 bytes
-rw-r--r--Master/texmf-dist/doc/latex/randexam/randexam.pdfbin45202 -> 50412 bytes
-rw-r--r--Master/texmf-dist/doc/latex/randexam/randexam.tex213
-rw-r--r--Master/texmf-dist/tex/latex/randexam/randexam.cls449
8 files changed, 532 insertions, 148 deletions
diff --git a/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.pdf b/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.pdf
index 732b941999f..d7d570e9b24 100644
--- a/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.pdf
+++ b/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex b/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex
index d431b45732e..fdfec30618d 100644
--- a/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex
+++ b/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex
@@ -12,11 +12,12 @@
\examtitle{name=Math 1906 Final Exam,date=2018-06-28,version=A} % make exam title
-\gradetable
+\gradetable[total=4]
-\examgroup{Fill in the blanks.}{6 questions; 3 points for each; 18 points in total.}
+\exampart{Fill in the blanks.}{6 questions; 3 points for each; 18 points in total.}
-\answertable[3em]{6}{3} % make answer table: height 3em, six in total, three for each row
+% make answer table: six in total, three for each row, strut height 3em
+\answertable[total=6,column=3,strut=3em]
\begin{question}
The first question $k>0$, text $f(x)=\ln x-\frac{x}{\e}+k$ text $(0,+\infty)$
@@ -70,9 +71,10 @@ text text text text text text text text text text $\xi-2\eta\sim$ \fillout{$N(-3
\newpage
-\examgroup{Select one answer from four choices.}{6 questions; 3 points for each; 18 points in total.}
+\exampart{Select one answer from four choices.}{6 questions; 3 points for each; 18 points in total.}
-\answertable{6}{6} % 生成答题栏:默认行高,总共8题,每行8题
+% make answer table: six in total, six for each row, default strut height
+\answertable[total=6,column=6]
\begin{question}
The first question text, text text text text text text text text text text
@@ -168,7 +170,7 @@ text text text text text text text text text text text text text text \pickout{D
\newpage
-\examgroup{Work out math questions.}{6 questions; 8 points for each; 48 points in total.}
+\exampart{Work out math questions.}{6 questions; 8 points for each; 48 points in total.}
\begin{question}
The first question $\int\e^{2x}\,(\tan x+1)^2\dx$.
@@ -305,9 +307,9 @@ Text text $H_0:\mu=3140$ text text ($\alpha = 0.01$).
\newpage
-\examgroup{Work out math proofs.}{2 questions; 16 points in total.}
+\exampart{Work out math proofs.}{2 questions; 16 points in total.}
-\renewcommand{\solutionname}{Proof} % 将“解”字改为“证”字
+\DeclareExamTranslation{current}{solution-Solution=Proof} % rename "Solution" as "Proof"
\begin{question}[points=9]
The first question $\{x_n\}$ text $x_1=\sqrt2$, $x_{n+1}=\sqrt{2+x_n}$.
diff --git a/Master/texmf-dist/doc/latex/randexam/randexam-a-blank.pdf b/Master/texmf-dist/doc/latex/randexam/randexam-a-blank.pdf
index 2da2d3748fe..1a85a26f4cd 100644
--- a/Master/texmf-dist/doc/latex/randexam/randexam-a-blank.pdf
+++ b/Master/texmf-dist/doc/latex/randexam/randexam-a-blank.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/randexam/randexam-b-answer.pdf b/Master/texmf-dist/doc/latex/randexam/randexam-b-answer.pdf
index 699a82d0551..349d3a80d95 100644
--- a/Master/texmf-dist/doc/latex/randexam/randexam-b-answer.pdf
+++ b/Master/texmf-dist/doc/latex/randexam/randexam-b-answer.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/randexam/randexam-b-blank.pdf b/Master/texmf-dist/doc/latex/randexam/randexam-b-blank.pdf
index e9dd01eab33..5ee6962d09c 100644
--- a/Master/texmf-dist/doc/latex/randexam/randexam-b-blank.pdf
+++ b/Master/texmf-dist/doc/latex/randexam/randexam-b-blank.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/randexam/randexam.pdf b/Master/texmf-dist/doc/latex/randexam/randexam.pdf
index 0c7f83abdf6..2faabec1c8d 100644
--- a/Master/texmf-dist/doc/latex/randexam/randexam.pdf
+++ b/Master/texmf-dist/doc/latex/randexam/randexam.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/randexam/randexam.tex b/Master/texmf-dist/doc/latex/randexam/randexam.tex
index 9e38395b94e..feb1af2e145 100644
--- a/Master/texmf-dist/doc/latex/randexam/randexam.tex
+++ b/Master/texmf-dist/doc/latex/randexam/randexam.tex
@@ -3,7 +3,7 @@
\documentclass[12pt,plain,most]{randexam}
\geometry{b5paper,margin=2cm}
-\newcommand*{\myversion}{2024B}
+\newcommand*{\myversion}{2024C}
\newcommand*{\mydate}{\the\year-\mylpad\month-\mylpad\day}
\newcommand*{\mylpad}[1]{\ifnum#1<10 0\the#1\else\the#1\fi}
@@ -46,6 +46,7 @@
\NewDocumentCommand\myfile{m}{\textcolor{purple3}{\mbox{#1}}}
\NewDocumentCommand\mykey{m}{\textcolor{brown3}{\mbox{\fakeverb{#1}}}}
\NewDocumentCommand\myval{m}{\textcolor{azure3}{\mbox{\fakeverb{#1}}}}
+\NewDocumentCommand\myelem{m}{\textcolor{violet3}{\mbox{#1}}}
\begin{document}
@@ -57,6 +58,7 @@
Title: \fillbox{\color{blue3}The randexam class for LaTeX}\\
Author: \fillbox{Jianrui Lyu (tolvjr@163.com)}\\
Version: \fillbox{\myversion{} (\mydate)}\\
+ Code: \fillbox{\url{https://github.com/lvjr/randexam}}\\
\hline
\end{tabularx}%
}
@@ -102,16 +104,16 @@ you add class option \myopt{random} (see Subsection \ref{opt:random}):
\subsection{Document body}
In document body you normally write an \mycmd{\examtitle},
-multiple \mycmd{\examgroup}, and an optional \mycmd{\examdata} commands:
+multiple \mycmd{\exampart}, and an optional \mycmd{\examdata} commands:
\begin{code}
\examtitle{name=Math Final Exam,date=2018-06-28,version=A}
......
-\examgroup{Fill in the blanks.}{3 points for each.}
+\exampart{Fill in the blanks.}{3 points for each.}
......
-\examgroup{Select one answer.}{3 points for each.}
+\exampart{Select one answer.}{3 points for each.}
......
-\examgroup{Work out math calculations.}{8 points for each.}
+\exampart{Work out math calculations.}{8 points for each.}
......
\examdata{Some data may be used in the exam}
......
@@ -130,16 +132,16 @@ If the \mykey{date} key is missing, it has the default value \myval{\today}.
When class option \myopt{random} is passed, the value of \mykey{version} key
will be modified from \myval{A} to \myval{B}.
-\subsection{Exam groups}
+\subsection{Exam parts}
-The questions in an exam could be separated into several groups:
+The questions in an exam could be separated into several parts:
\begin{code}
-\examgroup{Fill in the blanks.}{3 points for each.}
+\exampart{Fill in the blanks.}{3 points for each.}
......
-\examgroup{Select one answer.}{3 points for each.}
+\exampart{Select one answer.}{3 points for each.}
......
-\examgroup{Work out math calculations.}{8 points for each.}
+\exampart{Work out math calculations.}{8 points for each.}
......
\end{code}
@@ -160,7 +162,7 @@ or the exam variants will be incorrect.
\subsection{True-or-false questions}
\begin{code}
-\examgroup{True-or-false questions}{3 points for each.}
+\exampart{True-or-false questions}{3 points for each.}
\begin{question}
The first true-or-false question. \tickout{T}
@@ -189,7 +191,7 @@ so as to make \mypkg{randexam} hide them in generating blank exam papers.
\subsection{Fill-in-the-blank questions}
\begin{code}
-\examgroup{Fill in the blanks.}{3 points for each.}
+\exampart{Fill in the blanks.}{3 points for each.}
\begin{question}
The first fill-in-the-blank question \fillout{answer}.
@@ -217,7 +219,7 @@ so as to make \mypkg{randexam} hide them in generating blank exam papers.
\subsection{Multiple-choice questions}
\begin{code}
-\examgroup{Select one answer.}{3 points for each.}
+\exampart{Select one answer.}{3 points for each.}
\begin{question}
The first multiple-choice questions \pickout{A}.
@@ -275,7 +277,7 @@ according to the lengths of the choices.
For subjective questions, you could put answers inside \myenv{solution} environment.
\begin{code}
-\examgroup{Work out math calculations.}{8 points for each.}
+\exampart{Work out math calculations.}{8 points for each.}
\begin{question}
The first math calculation question.
@@ -315,7 +317,7 @@ Answer to the second question.
You can write other types of questions. For example:
\begin{code}
-\examgroup{Some question type}{4 points for each.}
+\exampart{Some question type}{4 points for each.}
\begin{question}
First question text. \answer{Answer text.}
@@ -345,10 +347,16 @@ Normally you need a grade table after exam title.
You can get it by using \mycmd{\gradetable} command.
\begin{code}
-\gradetable
+\gradetable[total=6,strut=2em]
\end{code}
-\gradetable
+\vspace{-1.5em}\gradetable[total=6,strut=2em]
+
+The meanings of keys in the \verb!\gradetable! command are:
+\begin{description}
+ \item[total] total number of parts in this exam.
+ \item[strut] strut height of the score row; its default value is \verb!2.5em!.
+\end{description}
\subsection{Answer tables}
@@ -356,17 +364,18 @@ Before true-or-false, fill-in-the-blank, or multiple-choice questions,
you may use \mycmd{\answertable} to generate an blank answer table:
\begin{code}
-\answertable[3em]{6}{3}
+\answertable[total=6,column=3,strut=3em]
\end{code}
-\answertable[3em]{6}{3}
+\answertable[total=6,column=3,strut=3em]
-The meanings of the three arguments of \verb!\answertable! commands are as follows:
-\begin{itemize}
- \item The first one means the strut height of the answer rows; its default value is \verb!1em!.
- \item The second one means the total number of questions in this exam group.
- \item The third one means the number of questions in each row.
-\end{itemize}
+The meanings of keys in the \verb!\answertable! command are:
+\begin{description}
+ \item[total] total number of questions in this exam part.
+ \item[column] number of questions in each row.
+ \item[strut] strut height of the answer rows; its default value is \verb!1em!.
+ \item[notice] notice text before the answer table.
+\end{description}
\subsection{Vertical space}
@@ -412,12 +421,13 @@ This is a question.
\subsection{Solution name}
-If you want to change the name of \myenv{solution} environment,
-you could redefine \mycmd{\solutionname} command.
+If you would like to change the name of \myenv{solution} environment,
+you could modify the translation of \mykey{solution-Solution} keyword
+(see Subsection \ref{subsect:translation}).
The following example changes it from "Solution" to "Proof":
\begin{code}
-\renewcommand{\solutionname}{Proof}
+\DeclareExamTranslation{current}{solution-Solution=Proof}
\end{code}
\subsection{Points command}
@@ -498,7 +508,7 @@ The answers will be hidden in the compiled exam paper.
\subsection{Randomized variants}\label{opt:random}
Assume \myfile{exam-a-answer.tex} is an exam paper.
-You can get an randomized variant with all questions in the same group shuffled,
+You can get an randomized variant with all questions in the same part shuffled,
by creating an \myfile{exam-b-answer.tex} file with the following lines:
\begin{code}
@@ -507,7 +517,7 @@ by creating an \myfile{exam-b-answer.tex} file with the following lines:
\end{code}
That is to say, when adding \myopt{random} option to \mypkg{randexam} class,
-The questions in the same group will be shuffled in the compiled exam paper.
+The questions in the same part will be shuffled in the compiled exam paper.
Furthermore, four choices in an \myenv{abcd} environment will be shuffled too.
\subsection{Two column exam papers}
@@ -538,4 +548,147 @@ by creating a new TeX file with the following lines:
That is to say, you can make an exam of A3 size from an exam of A4 size,
even if you have only the PDF file.
+\section{Customizations}
+
+\subsection{Translations of keywords}\label{subsect:translation}
+
+With \mycmd{\DeclareExamTranslation} you can define the translaitons of the keywords
+in an \mypkg{randexam} paper. At this time only English keywords are defined:
+
+\begin{code}
+\DeclareExamTranslation{english}{
+ answertable-Answer = Answer
+ ,answertable-Number = Number
+ ,examdata-Appendix = Appendix
+ ,exampart-Part = Part
+ ,examtitle-Name = Name
+ ,examtitle-Solutions = Solutions
+ ,gradetable-Evaluator = Evaluator
+ ,gradetable-Part = Part
+ ,gradetable-Score = Score
+ ,gradetable-Total = Total
+ ,headfoot-Name = Name
+ ,headfoot-of = of
+ ,headfoot-Page = Page
+ ,headfoot-Solutions = Solutions
+ ,headfoot-Version = Version
+ ,points-point = point
+ ,points-points = points
+ ,question-Question = Question
+ ,solution-Solution = Solution
+}
+\end{code}
+
+You could translate them for another language and enable them with \mycmd{\SelectExamTranslation} command:
+
+\begin{code}
+\DeclareExamTranslation{somelang}{
+ question-Question = Questioooooon
+ ,solution-Solution = Soooooolution
+}
+\SelectExamTranslation{somelang}
+\end{code}
+\DeclareExamTranslation{somelang}{
+ question-Question = Questioooooon
+ ,solution-Solution = Soooooolution
+}
+\SelectExamTranslation{somelang}
+
+After this, you could load current translation of some keywords with \mycmd{\UseExamTranslation} command:
+
+\begin{code}
+\UseExamTranslation{question-Question}
+\UseExamTranslation{solution-Solution}
+\end{code}
+\hrule
+\UseExamTranslation{question-Question}
+\UseExamTranslation{solution-Solution}
+\vspace{0.5em}
+\hrule
+\vspace{0.5em}
+
+\SelectExamTranslation{english}
+
+This command is useful in defining new templates for the exam (see Subsection \ref{subsect:template}).
+
+\subsection{Saving and reading key values}
+
+With \mycmd{\DeclareExamValue} and \mycmd{\UseExamValue} you could save and read
+the value of a key, respectively.
+
+\begin{code}
+\DeclareExamValue{somemodule}{somekey}{SomeValue}
+\UseExamValue{somemodule}{somekey}
+\end{code}
+\hrule
+\DeclareExamValue{somemodule}{somekey}{SomeValue}
+\UseExamValue{somemodule}{somekey}
+\vspace{0.5em}
+\hrule
+\vspace{0.5em}
+
+These two commands are useful in defining new templates
+for the exam (see Subsection \ref{subsect:template}).
+
+\subsection{Templates of elements}\label{subsect:template}
+
+With \mycmd{\DeclareExamTemplate} you could define a new template for some exam element,
+which could be set as default template with \mycmd{\SelectExamTemplate}.
+And with \mycmd{\UseExamTemplate} you could use the default template of the element.
+
+To customize \myelem{examtitle} element for your school,
+you can write the following code in document preamble:
+\begin{code}
+\DeclareExamTemplate{examtitle}{myschool}{%
+ \fbox{%
+ \UseExamValue{examtitle}{name}\quad%
+ \UseExamValue{examtitle}{date}%
+ }%
+}%
+\SelectExamTemplate{examtitle}{myschool}
+\end{code}
+\DeclareExamTemplate{examtitle}{myschool}{%
+ \fbox{%
+ \UseExamValue{examtitle}{name}\quad%
+ \UseExamValue{examtitle}{date}%
+ }%
+}%
+\SelectExamTemplate{examtitle}{myschool}
+
+Then the \mycmd{\examtitle} command in document body will produce different result:
+\begin{code}
+\examtitle{name=Final Exam in My School,date=2024-01-01}
+\end{code}
+\vspace{-1em}
+\examtitle{name=Final Exam in My School,date=2024-01-01}
+
+Normally \mycmd{\examtitle} will call \mycmd{\UseExamTemplate{examtitle}{default}}.
+
+All elements that could be customized with templates in an exam paper
+are listed in the following table:
+
+\begingroup\renewcommand\arraystretch{1.5}\noindent
+\begin{tabularx}{\linewidth}{ll}
+\hline
+ \myelem{examtitle} & for customizing \mycmd{\examtitle} command \\
+\hline
+ \myelem{exampart} & for customizing \mycmd{\exampart} command \\
+\hline
+ \myelem{examdata} & for customizing \mycmd{\examdata} command \\
+\hline
+ \myelem{gradetable} & for customizing \mycmd{\gradetable} command \\
+\hline
+ \myelem{answertable} & for customizing \mycmd{\answertable} command \\
+\hline
+ \myelem{questionbegin} & for customizing \myenv{question} environment \\
+\hline
+ \myelem{questionend} & for customizing \myenv{question} environment \\
+\hline
+ \myelem{solutionbegin} & for customizing \myenv{solution} environment \\
+\hline
+ \myelem{solutionend} & for customizing \myenv{solution} environment \\
+\hline
+\end{tabularx}\par
+\endgroup
+
\end{document}
diff --git a/Master/texmf-dist/tex/latex/randexam/randexam.cls b/Master/texmf-dist/tex/latex/randexam/randexam.cls
index 8f5ae8bde9b..d103dfe5584 100644
--- a/Master/texmf-dist/tex/latex/randexam/randexam.cls
+++ b/Master/texmf-dist/tex/latex/randexam/randexam.cls
@@ -5,9 +5,9 @@
% ----------------------------------------------------------------------------
\NeedsTeXFormat{LaTeX2e}
-\ProvidesClass{randexam}[2024-01-20 v2024B Make an exam paper and its randomized variants]
+\ProvidesClass{randexam}[2024-01-28 v2024C Make an exam paper and its randomized variants]
-%% Old LaTeX release could not recongnize date format like 2022-11-01
+%% Old LaTeX release could not recognize date format like 2022-11-01
%\@ifl@t@r\fmtversion{2022-11-01}{}{
\@ifl@t@r\fmtversion{2022/11/01}{}{
\ClassError{randexam}{%
@@ -16,6 +16,9 @@
}{Please update your TeX distribution first.}
}
+\RequirePackage{functional}
+\IgnoreSpacesOn
+
\RequirePackage{etoolbox}
\newbool{plain} \boolfalse{plain} % use plain page style
@@ -27,7 +30,7 @@
\newbool{amsfonts} \boolfalse{amsfonts} % use ams fonts
\newbool{freealign} \boolfalse{freealign} % load freealign package
\newbool{medmath} \boolfalse{medmath} % use medium-size formulas
-\newbool{grader} \boolfalse{grader} % add grader line in the grade table
+\newbool{evaluator} \boolfalse{evaluator} % add evaluator line in the grade table
\DeclareKeys{
plain .if = plain,
@@ -39,7 +42,7 @@
amsfonts .if = amsfonts,
freealign .if = freealign,
medmath .if = medmath,
- grader .if = grader,
+ evaluator .if = evaluator,
many .code = \booltrue{freealign},
most .code = \booltrue{freealign}\booltrue{medmath}
}
@@ -66,7 +69,6 @@
\RequirePackage{zref-user,zref-lastpage}
\RequirePackage{tabularx}
\RequirePackage{xcolor}
-\RequirePackage{xkeyval}
\ifplain
\allowdisplaybreaks[4]
@@ -91,6 +93,103 @@
\NewDocumentCommand\SetExamOption{+m}{\SetKeys[randexam]{#1}}
%% ---------------------------------------------------------------------------
+%% Template commands for exam elements
+%% ---------------------------------------------------------------------------
+
+%% #1: exam element; #2: template name; #3: template code
+%% If the template name = default, we enable the template at once
+%% Otherwise, we may enable the template by using \SelectExamTemplate command
+\NewDocumentCommand\DeclareExamTemplate{mm+m}{
+ \tlSet{\expName{l@rdxm@template@#1@#2@tl}}{#3}
+ \ignorespaces
+}
+
+%% #1: exam element; #2: template name
+\NewDocumentCommand\SelectExamTemplate{mm}{
+ \tlSetEq{\expName{l@rdxm@template@#1@default@tl}}{\expName{l@rdxm@template@#1@#2@tl}}
+ \ignorespaces
+}
+
+%% #1: exam element; #2: template name.
+%% In an expandable command, we should use \UseName but not \expName.
+\NewExpandableDocumentCommand\UseExamTemplate{mm}{
+ \UseName{l@rdxm@template@#1@#2@tl}
+}
+
+%% ---------------------------------------------------------------------------
+%% Translation commands for exam keywords
+%% ---------------------------------------------------------------------------
+
+\tlSet\l@rdxm@current@language@tl{english}
+
+\DeclareUnknownKeyHandler[randexam-translation]{
+ \tlSet{\expName{l@rdxm@translate@\l@rdxm@declare@language@tl @#1@tl}}{#2}
+}
+
+%% #1: language name; #2: a keyval list with keyword = transaltion format
+\NewDocumentCommand\DeclareExamTranslation{mm}{
+ \tlIfEqTF{#1}{current}{
+ \tlSetEq\l@rdxm@declare@language@tl\l@rdxm@current@language@tl
+ }{
+ \tlSet\l@rdxm@declare@language@tl{#1}
+ }
+ \SetKeys[randexam-translation]{#2}
+ \ignorespaces
+}
+
+%% #1: language name
+\NewDocumentCommand\SelectExamTranslation{m}{
+ \tlSet\l@rdxm@current@language@tl{#1}
+ \ignorespaces
+}
+
+%% #1: keyword name.
+%% In an expandable command, we should use \UseName but not \expName.
+\NewExpandableDocumentCommand\UseExamTranslation{m}{
+ \UseName{l@rdxm@translate@\l@rdxm@current@language@tl @#1@tl}
+}
+
+\DeclareExamTranslation{english}{
+ answertable-Answer = Answer
+ ,answertable-Number = Number
+ ,examdata-Appendix = Appendix
+ ,exampart-Part = Part
+ ,examtitle-Name = Name
+ ,examtitle-Solutions = Solutions
+ ,gradetable-Evaluator = Evaluator
+ ,gradetable-Part = Part
+ ,gradetable-Score = Score
+ ,gradetable-Total = Total
+ ,headfoot-Name = Name
+ ,headfoot-of = of
+ ,headfoot-Page = Page
+ ,headfoot-Solutions = Solutions
+ ,headfoot-Version = Version
+ ,points-point = point
+ ,points-points = points
+ ,question-Question = Question
+ ,solution-Solution = Solution
+}
+
+\SelectExamTranslation{english}
+
+%% ---------------------------------------------------------------------------
+%% Keyvalue commands for exam options
+%% ---------------------------------------------------------------------------
+
+%% #1 module name; #2: key name; #3: its value
+\NewDocumentCommand\DeclareExamValue{mm+m}{
+ \tlSet{\expName{l@rdxm@value@#1@#2@tl}}{#3}
+ \ignorespaces
+}
+
+%% #1: module name; #2: key name.
+%% In an expandable command, we should use \UseName but not \expName.
+\NewExpandableDocumentCommand\UseExamValue{mm}{
+ \UseName{l@rdxm@value@#1@#2@tl}
+}
+
+%% ---------------------------------------------------------------------------
%% Command for exam title: \examtitle
%% ---------------------------------------------------------------------------
@@ -101,88 +200,143 @@
\newcommand{\ischeck}[1]{\ifnum#1>0\,$\checkmark$\,\else\quad\fi}
\newcommand{\isquad}[1]{\ifnum#1=0\,$\checkmark$\,\else\quad\fi}
-\def\rdxm@temp@a{A}
-\def\rdxm@temp@c{C}
-\def\rdxm@empty{}
-
\DeclareKeys[randexam-title]{
- name .store = \@rdxm@title@name,
- date .store = \@rdxm@title@date,
- version .store = \@rdxm@title@version
+ name .code = \DeclareExamValue{examtitle}{name}{#1}
+ ,date .code = \DeclareExamValue{examtitle}{date}{#1}
+ ,version .code = \DeclareExamValue{examtitle}{version}{#1}
}
\NewDocumentCommand\SetExamTitle{+m}{\SetKeys[randexam-title]{#1}}
-\SetExamTitle{name=Math 1906,date=\today,version=A}
+\SetExamTitle{name=Math~1906,date=\today,version=A}
-\newcommand\examtitle[1]{%
- \SetExamTitle{#1}%
- \thispagestyle{plain}
- \ifbool{random}{%
- \ifx\@rdxm@title@version\rdxm@temp@a\def\@rdxm@title@version{B}\fi
- \ifx\@rdxm@title@version\rdxm@temp@c\def\@rdxm@title@version{D}\fi
- }{}%
+\DeclareExamTemplate{examtitle}{normal}{
\begingroup
\Large\noindent
- \ifbool{answer}{%
- \textcolor{red!80!black}{\@rdxm@title@name\hfill Solutions}%
- }{%
- \@rdxm@title@name\hfill Name:\underspace{6em}%
+ \ifbool{answer}{
+ \textcolor{red!80!black}{
+ \UseExamValue{examtitle}{name}\hfill\UseExamTranslation{examtitle-Solutions}
+ }
+ }{
+ \UseExamValue{examtitle}{name}\hfill\UseExamTranslation{examtitle-Name}:\underspace{6em}
}\par
\endgroup
}
+\SelectExamTemplate{examtitle}{normal}
+
+\NewDocumentCommand\examtitle{+m}{
+ \SetExamTitle{#1}
+ \thispagestyle{plain}
+ \ifbool{random}{
+ \tlIfEqT{\expWhole{\UseExamValue{examtitle}{version}}}{A}{
+ \DeclareExamValue{examtitle}{version}{B}
+ }
+ \tlIfEqT{\expWhole{\UseExamValue{examtitle}{version}}}{C}{
+ \DeclareExamValue{examtitle}{version}{D}
+ }
+ }{}
+ \UseExamTemplate{examtitle}{default}
+}
%% ---------------------------------------------------------------------------
%% Command for grade table: \gradetable
%% ---------------------------------------------------------------------------
-%% You need to put .code:n before .initial:n
-\DeclareKeys[randexam]{%
- groupnumber .code:n = \let\exam@group@number#1,
- groupnumber .initial:n = \Roman,
+%% total: total number of parts in current exam;
+%% strut: strut height in the score row.
+\DeclareKeys[randexam-gradetable]{
+ total .code = \DeclareExamValue{gradetable}{total}{#1}
+ ,total .initial:n = 6
+ ,strut .code = \DeclareExamValue{gradetable}{strut}{#1}
+ ,strut .initial:n = 2.5em
}
\newcounter{@exam@grade@cnt}
-\newcommand\rdxm@group@number[1]{%
- \stepcounter{@exam@grade@cnt}%
- \exam@group@number{@exam@grade@cnt}%
+\newrobustcmd\rdxm@part@number[1]{
+ \setcounter{@exam@grade@cnt}{#1}
+ \exam@part@number{@exam@grade@cnt}
}
-\newcommand\insertgroupname{Part}
-\newcommand\insertscorename{Score}
-\newcommand\insertgradername{Grader}
-\newcommand\inserttotalname{Total}
+%% #1: the tl variable; #2: the first cell; #3: the last cell
+%% #4: the number of middle cells; #5: the map command for middle cells.
+\newrobustcmd\rdxm@table@make@row[5]{
+ \tlSet#1{#2 & }
+ \intStepOneInline{1}{#4}{
+ \tlPutRight#1{#5{##1} &}
+ }
+ \tlPutRight#1{ #3}
+}
-\newcommand\gradetable{%
- \par\vspace{1em}%
- \setcounter{@exam@grade@cnt}{0}%
- \noindent\begin{tabularx}{\linewidth}{|*{8}{Y|}}
- \hline
- \textbf{\insertgroupname}
- & \rdxm@group@number{1} & \rdxm@group@number{2} & \rdxm@group@number{3}
- & \rdxm@group@number{4} & \rdxm@group@number{5} & \rdxm@group@number{6}
- & \inserttotalname\\
- \hline
- \textbf{\insertscorename}\rule[-0.75em]{0pt}{2.5em} & & & & & & & \\
+\newrobustcmd\rdxm@gobble@one[1]{}
+
+%% \dimeval or \dimexpr doesn't accept decimal numbers such as 0.3
+\NewDocumentCommand\MakeExamStruct{m}{
+ \rule[-\dimeval{(#1)*3/10}]{0pt}{#1}
+}
+
+\DeclareExamTemplate{gradetable}{normal}{
+ \rdxm@table@make@row
+ \l@rdxm@gradetable@part@tl
+ {\textbf{\UseExamTranslation{gradetable-Part}}}
+ {\UseExamTranslation{gradetable-Total}}
+ {\UseExamValue{gradetable}{total}}
+ \rdxm@part@number
+ \rdxm@table@make@row
+ \l@rdxm@gradetable@score@tl
+ {\textbf{\UseExamTranslation{gradetable-Score}}
+ \MakeExamStruct{\UseExamValue{gradetable}{strut}}}
+ {}
+ {\UseExamValue{gradetable}{total}}
+ \rdxm@gobble@one
+ \ifbool{evaluator}{
+ \rdxm@table@make@row
+ \l@rdxm@gradetable@evaluator@tl
+ {\textbf{\UseExamTranslation{gradetable-Evaluator}}
+ \MakeExamStruct{\UseExamValue{gradetable}{strut}}}
+ {}
+ {\UseExamValue{gradetable}{total}}
+ \rdxm@gobble@one
+ }{}
+ \noindent
+ \begin{tabularx}{\linewidth}{|c|*{\UseExamValue{gradetable}{total}}{Y|}Y|}
\hline
- \ifbool{grader}{
- \textbf{\insertgradername}\rule[-0.75em]{0pt}{2.5em} & & & & & & & \\
- \hline
- }{}
+ \l@rdxm@gradetable@part@tl \\ \hline
+ \l@rdxm@gradetable@score@tl \\ \hline
+ \ifbool{evaluator}{\l@rdxm@gradetable@evaluator@tl \\ \hline}{}
\end{tabularx}
}
+\SelectExamTemplate{gradetable}{normal}
+
+\NewDocumentCommand\gradetable{O{}}{
+ \par\vspace{1em}
+ \begingroup
+ \SetKeys[randexam-gradetable]{#1}
+ \UseExamTemplate{gradetable}{default}
+ \endgroup
+}
%% ---------------------------------------------------------------------------
%% Setting header and footer
%% ---------------------------------------------------------------------------
\newcommand{\rdxm@columnbox}[1]{\makebox[\columnwidth]{#1}}
-\newcommand{\rdxm@headleft}{\@rdxm@title@name}
-\newcommand{\rdxm@headright}{\ifbool{answer}{Solutions}{Name:\hspace{12em}}}
+\newcommand{\rdxm@headleft}{\UseExamValue{examtitle}{name}}
+\newcommand{\rdxm@headright}{
+ \ifbool{answer}{
+ \UseExamTranslation{headfoot-Solutions}
+ }{
+ \UseExamTranslation{headfoot-Name}:\hspace{12em}
+ }
+}
\newcommand{\rdxm@headtext}{\rdxm@headleft\hfill\rdxm@headright}
-\newcommand{\rdxm@footleft}{\@rdxm@title@date}
-\newcommand{\rdxm@footcenter}{Page~\thepage~of~\zpageref{LastPage}}
-\newcommand{\rdxm@footright}{Version \@rdxm@title@version}
+\newcommand{\rdxm@footleft}{\UseExamValue{examtitle}{date}}
+\newcommand{\rdxm@footcenter}{
+ \UseExamTranslation{headfoot-Page}~\thepage\space
+ \UseExamTranslation{headfoot-of}~\zpageref{LastPage}
+}
+\newcommand{\rdxm@footright}{
+ \UseExamTranslation{headfoot-Version}~\UseExamValue{examtitle}{version}
+}
\newcommand{\rdxm@foottext}{\rdxm@footleft\hfill\rdxm@footcenter\hfill\rdxm@footright}
% fancy page style
@@ -235,7 +389,7 @@
\RequirePackage{pgffor}
\newcommand*\exam@set@seed{%
%% 当\pgfmathrandom的参数为3的倍数时,对相邻种子生成的多个随机数分布不均匀
- %\pgfmathsetseed{\numexpr\rdxm@random@seed+\value{rdxm@group}-1\relax}%
+ %\pgfmathsetseed{\numexpr\rdxm@random@seed+\value{rdxm@part}-1\relax}%
%% 因此我们改用下面的方法,用随机数种子生成下一个随机数种子
\pgfmathsetseed{\rdxm@random@seed}%
\pgfmathrandominteger\rdxm@random@seed{1}{2147483647}%
@@ -243,25 +397,31 @@
\fi
%% ---------------------------------------------------------------------------
-%% Command for exam groups: \examgroup
+%% Command for exam groups: \exampart
%% Command for appendix data: \examdata
%% Environment for questions: question
%% Environment for solutions: solution
%% ---------------------------------------------------------------------------
+%% You need to put .code before .initial:n
+\DeclareKeys[randexam-exampart]{%
+ partnumber .code = \let\exam@part@number#1,
+ partnumber .initial:n = \Roman,
+}
+
\newif\ifonlyonequestion \onlyonequestionfalse % 此部分仅有一道题时不显示题目编号
\xdef\allquestions{}
\xdef\lastquestion{}
\newcounter{question} % 当前题型的小题编号
\newcounter{questionreal} % 实际显示的小题编号,在各题型小题统一编号时使用
\newcounter{totalquestions} % 之前各题型小题总数,在各题型小题统一编号时使用
-\newcommand{\solutionname}{Solution}
+
\newcounter{choice} % 后面选择题的 abcd 环境要用到
\newcommand{\hangtext}{}
\newlength{\hanglength}
-\colorlet{group number}{black}
-\colorlet{question number}{blue!80!black}
-\colorlet{solution name}{blue!80!black}
+\colorlet{part~number}{black}
+\colorlet{question~number}{blue!80!black}
+\colorlet{solution~name}{blue!80!black}
\newcounter{rdxm@shuffle@temp@cnt}
\newcounter{rdxm@list@temp@cnt}
@@ -337,19 +497,29 @@
\xdef\lastquestion{}%
}
-\newcounter{rdxm@group}
+\newcounter{rdxm@part}
-\newcommand\insertgroup[2]{%
- \noindent\textbf{\textcolor{group number}{Part~\Roman{rdxm@group}}: #1} (#2)%
+\DeclareExamTemplate{exampart}{normal}{
+ \noindent
+ \textbf{
+ \textcolor{part~number}{\UseExamTranslation{exampart-Part}~\Roman{rdxm@part}}
+ :~\UseExamValue{exampart}{type}
+ }
+ \space(\UseExamValue{exampart}{points})
}
+\SelectExamTemplate{exampart}{normal}
-\newcommand{\examgroup}[2]{%
+\newcommand{\exampart}[2]{
\printquestions
- \setcounter{totalquestions}{\value{totalquestions}+\value{question}}%
- \setcounter{question}{0}%
- \stepcounter{rdxm@group}%
- \vspace{1em}%
- \insertgroup{#1}{#2}%
+ \setcounter{totalquestions}{\value{totalquestions}+\value{question}}
+ \setcounter{question}{0}
+ \stepcounter{rdxm@part}
+ \vspace{1em}
+ \begingroup
+ \DeclareExamValue{exampart}{type}{#1}
+ \DeclareExamValue{exampart}{points}{#2}
+ \UseExamTemplate{exampart}{default}
+ \endgroup
\par\nopagebreak
\if\relax\detokenize{#1}\relax % #1 is empty
\onlyonequestiontrue
@@ -361,57 +531,96 @@
\@afterheading
}
-\renewcommand\appendixname{Appendix}
-\newcommand{\examdata}[1]{%
+\DeclareExamTemplate{examdata}{normal}{
+ \centerline{
+ \textbf{\UseExamTranslation{examdata-Appendix}}
+ \quad\UseExamValue{examdata}{caption}
+ }
+ \smallskip
+}
+\SelectExamTemplate{examdata}{normal}
+
+\NewDocumentCommand\examdata{+m}{
\printquestions\rdxm@stop@random
- \centerline{\textbf{\appendixname}\quad #1}\smallskip
+ \DeclareExamValue{examdata}{caption}{#1}
+ \UseExamTemplate{examdata}{default}
}
\preto{\@enddocumenthook}{\printquestions\rdxm@stop@random}
\newcommand\ignorepars{\@ifnextchar\par{\expandafter\ignorepars\@gobble}{}}
-% 局部定义,仅在当前题目内有效
-\define@key{exam@question}{points}[-1]{\def\rdxm@question@points{#1}}
-\define@key{exam@question}{level}[]{\def\rdxm@question@level{#1}}
-\define@key{exam@question}{year}[]{\def\rdxm@question@year{#1}}
+% local definition, valid only in current question
+\DeclareKeys[randexam-question]{
+ points .store = \l@rdxm@question@points
+ ,level .store = \l@rdxm@question@level
+ ,year .store = \l@rdxm@question@year
+}
-\newcommand\pointname{point}
-\newcommand\pointsname{points}
-\newcommand\pointorpoints[1]{\ifnumgreater{#1}{1}{\pointsname}{\pointname}}
+\newcommand\pointorpoints[1]{
+ \ifnumgreater{#1}{1}{
+ \UseExamTranslation{points-points}
+ }{
+ \UseExamTranslation{points-point}
+ }
+}
\newcommand{\questionpointstext}[1]{ (#1 \pointorpoints{#1}) }
\newcommand\rdxm@hook@exec@other@keys{}
-\newcommand{\execute@question@keys}[1]{%
- \setkeys{exam@question}{#1}%
+\newrobustcmd\execute@question@keys{
\rdxm@hook@exec@other@keys
- \ifdefvoid{\rdxm@question@points}{}{\questionpointstext{\rdxm@question@points}}%
+ \ifdefvoid{\l@rdxm@question@points}{}{\questionpointstext{\l@rdxm@question@points}}
}
-\newenvironment{questionreal}[1][]{%
- \stepcounter{question}\setcounter{choice}{0}%
+\DeclareExamTemplate{questionbegin}{normal}{
\ifresetnumber
\ifonlyonequestion
\renewcommand{\hangtext}{\qquad}%
\else
- \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{question number}{\arabic{question}}.}}\;\,}%
+ \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{question~number}{\arabic{question}}.}}\;\,}
\fi
\else
\setcounter{questionreal}{\value{totalquestions}+\value{question}}%
- \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{question number}{\arabic{questionreal}}.}}\;\,}%
+ \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{question~number}{\arabic{questionreal}}.}}\;\,}
\fi
- \settowidth{\hanglength}{\hangtext}%
+ \settowidth{\hanglength}{\hangtext}
\description[leftmargin=\hanglength,labelwidth=0pt,labelsep=0pt,topsep=0pt,parsep=0pt]
- \item[\hangtext]\execute@question@keys{#1}%
-}{\enddescription}
-\newenvironment{solutionreal}{%
- \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{solution name}{\solutionname}.}}\;\,}%
- \settowidth{\hanglength}{\hangtext}%
+ \item[\hangtext]\execute@question@keys
+}
+\SelectExamTemplate{questionbegin}{normal}
+
+\DeclareExamTemplate{questionend}{normal}{\enddescription}
+\SelectExamTemplate{questionend}{normal}
+
+\NewDocumentEnvironment{questionreal}{O{}}{
+ \stepcounter{question}
+ \setcounter{choice}{0}
+ \SetKeys[randexam-question]{#1}
+ \UseExamTemplate{questionbegin}{default}
+}{
+ \UseExamTemplate{questionend}{default}
+}
+
+\DeclareExamTemplate{solutionbegin}{normal}{
+ \renewcommand{\hangtext}{
+ \textbf{\textsf{\textcolor{solution~name}{\UseExamTranslation{solution-Solution}}.}}\;\,
+ }
+ \settowidth{\hanglength}{\hangtext}
\description[leftmargin=\hanglength,labelwidth=0pt,labelsep=0pt,topsep=0pt,parsep=0pt]
\item[\hangtext]
-}{\enddescription}
+}
+\SelectExamTemplate{solutionbegin}{normal}
+
+\DeclareExamTemplate{solutionend}{normal}{\enddescription}
+\SelectExamTemplate{solutionend}{normal}
+
+\NewDocumentEnvironment{solutionreal}{}{
+ \UseExamTemplate{solutionbegin}{default}
+}{
+ \UseExamTemplate{solutionend}{default}
+}
\let \oldnewpage = \newpage
\let \oldvfill = \vfill
@@ -480,28 +689,37 @@
%% Command for answer tables: \answertable
%% ---------------------------------------------------------------------------
+%% property .store is the same as .tl_set:N in ltkeys.
+%% you need to put .code before .initial:n.
+%% total: total number of questions in current exam part;
+%% column: number of questions in each answer row;
+%% strut: strut height in each answer rows;
+%% notice: notice text before the answer table.
+\DeclareKeys[randexam-answertable]{
+ total .code = \DeclareExamValue{answertable}{total}{#1}
+ ,column .code = \DeclareExamValue{answertable}{column}{#1}
+ ,strut .code = \DeclareExamValue{answertable}{strut}{#1}
+ ,strut .initial:n = 1em
+ ,notice .code = \DeclareExamValue{answertable}{notice}{#1}
+ ,notice .initial:n = {Notice:~you~MUST~write~the~answers~in~the~following~tables.}
+}
+
\gdef\answer@lines@temp{}%
\newcommand{\answer@lines@add}[1]{%
\xdef\answer@lines@temp{\answer@lines@temp#1}%
}
-\newcommand\insertnumbertext{Number}
-\newcommand\insertanswertext{Answer}
-\newcommand\insertanswertabletext{%
- Notice: you MUST write the answers in the following tables.%
+\newrobustcmd\answer@number@hided[1]{\UseExamTranslation{answertable-Number}}
+\newrobustcmd\answer@cell@strut[1]{
+ \parbox[c][#1][c]{2em}{\hbox{\UseExamTranslation{answertable-Answer}}}
}
-\newrobustcmd{\answer@number@hided}[1]{\insertnumbertext} % 在 PDFLaTeX 中需要保护中文
-\newrobustcmd{\answer@cell@strut}[1]{\parbox[c][#1][c]{2em}{\hbox{\insertanswertext}}}
-
\newcounter{answer@col}
\newcounter{answer@row}
\newcounter{answer@total}
+%% #1: strut; #2: total; #3: column.
\newcommand{\answer@lines}[3]{%
- % #1 答题栏各栏指定高度
- % #2 答题栏总共答案个数
- % #3 答题栏每行答案个数
\setcounter{answer@row}{(#2-1)/#3+1}% 除法向下取整,改为向上取整
\begingroup
\let\hline=\relax \let\\=\relax % 禁止展开
@@ -537,13 +755,22 @@
\answer@lines@temp
}
-\newcommand{\answertable}[3][1em]{%
- \insertanswertabletext\par
- \begin{tabularx}{\linewidth}{|c|*{#3}{Y|}}
+\DeclareExamTemplate{answertable}{normal}{
+ \UseExamValue{answertable}{notice}\par
+ \begin{tabularx}{\linewidth}{|c|*{\UseExamValue{answertable}{column}}{Y|}}
\hline
- \answer@lines{#1}{#2}{#3}
- \end{tabularx}%
- \par\vspace{0.8em}%
+ \answer@lines{\UseExamValue{answertable}{strut}}
+ {\UseExamValue{answertable}{total}}{\UseExamValue{answertable}{column}}
+ \end{tabularx}
+}
+\SelectExamTemplate{answertable}{normal}
+
+\NewDocumentCommand\answertable{O{}}{
+ \begingroup
+ \SetKeys[randexam-answertable]{#1}
+ \UseExamTemplate{answertable}{default}
+ \endgroup
+ \par\vspace{0.8em}
}
%% ---------------------------------------------------------------------------
@@ -940,3 +1167,5 @@
\let \downwhitearrow = \Downarrow
}}
+\IgnoreSpacesOff
+